美文网首页activiti工作流
activiti6.0源码剖析之事件处理器(Event Hand

activiti6.0源码剖析之事件处理器(Event Hand

作者: 我有一只喵喵 | 来源:发表于2019-04-01 10:57 被阅读13次

    前言

    activiti为各种事件以及事件的发生类型提供了监听处理的功能。Activiti引擎中的事件机制允许我们在引擎中发生各种事件时得到通知从而处理我们的逻辑。所谓事件就是流程引擎中一些动作的发生,比如流程引擎的创建和关闭,流程变量的创建更新删除,任务的完成,流程实例的完成都称为是一个事件。那么activiti内部是如何实现对这些事件的监听呢?

    在介绍如何使用以及原理之前先介绍贯穿整个事件机制的三个元素。
    • 事件(ActivitiEvent)
      所谓事件的定义在前言中已做描述,所有的事件都应该是org.activiti.engine.delegate.event.ActivitiEvent的子类。每个事件都会提供可用的type(事件类型),executionId(执行实例Id),processInstanceId(流程实例Id),processDefinitionId(流程定义Id)。

    • 事件监听器(ActivitiEventListener)
      所谓事件监听器就是监听事件的状态,当事件的状态发生改变,就会通知触发事件监听器中的逻辑。所有的事件监听器都应该实现org.activiti.engine.delegate.event.ActivitiEventListener,并实现它的onEvent,isFailOnException两个方法。当事件状态发生变化就会触发onEvent方法,此方法持有事件实例,如果在onEvent中执行逻辑发生了异常,则程序会触发isFailOnException方法,如果认为该异常没有什么影响可以通过返回false忽略该异常,否则返回true,此时异常不会被忽略,并且冒泡从而导致此前的命令失败。activiti内部提供了一个ActivitiEventListener的base实现类BaseEntityEventListener,它提供了Entity事件的创建onCreate(..),更新onUpdate(..),删除onDelete(..)的监听操作

    • 事件转发器(ActivitiEventDispatcher)
      activiti引擎是如何在配置了事件监听器后,监听到各类事件的一系列动作呢?这里就到事件转发器出场了,当各类事件状态发生改变时,都会调用ActivitiEventDispatcher来转发事件,之后事件转发器就会在遍历所有的事件监听器,当检测到某监听器符合当前事件时,就会通过ActivitiEventDispatcher的dispatchEvent以当前事件为参数进行转发调用相应监听器的onEvent方法。所以也就达到了监听的效果。 activiti中提供了ActivitiEventDispatcher的实现类ActivitiEventDispatcherImpl

    接下来走进实战


    一、实现监听器

    实现ActivitiEventListener接口,实现onEvent,isFailOnException方法

    public class MyEventListener implements ActivitiEventListener {
    
        public void onEvent(ActivitiEvent activitiEvent) {
            System.out.println(activitiEvent.getType());
            System.out.println(activitiEvent.getExecutionId());
            System.out.println(activitiEvent.getProcessDefinitionId());
            System.out.println(activitiEvent.getProcessInstanceId());
        }
    
        public boolean isFailOnException() {
            System.out.println("发生异常");
            return false;
        }
    }
    

    二、配置事件监听器

    2.1、通过ProcessEngineConfiguration配置监听器

    事件监听器配置在ProcessEngineConfiguration种,ProcessEngineConfiguration有两个事件监听器属性:

    • eventListeners
      protected List<ActivitiEventListener> eventListeners
      该属性是一个list集合,配置在这里的监听器相当于全局事件监听器,也就是监听所有事件类型发生的各类型动作。
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        ...
        <property name="eventListeners">
          <list>
             <bean class="cn.cf.MyEventListener" />
          </list>
        </property>
    </bean>
    
    • typedEventListeners
      protected Map<String, List<ActivitiEventListener>> typedEventListeners;
      该属性是一个map集合,该map中的监听器监听某种指定类型的事件,key为事件类型,value是一个监听器集合
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        ...
        <property name="typedEventListeners">
          <map>
            <entry key="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" >
              <list>
                <bean class="cn.cf.MyJobEventListener" />
              </list>
            </entry>
          </map>
        </property>
    </bean>
    

    这里通过配置activiti.cfg.xml中的ProcessEngineConfiguration添加事件监听器。除了这种方式,我们还可以在运行时动态添加监听器。但是此种方法在流程引擎重启之后就会消失。

    • RuntimeService相关Api
       void addEventListener(ActivitiEventListener var1);
    
       void addEventListener(ActivitiEventListener var1, ActivitiEventType... var2);
    
       void removeEventListener(ActivitiEventListener var1);
    
       void dispatchEvent(ActivitiEvent var1);
    

    从上述API中看出,我们也可以通过RuntimeService手动转发事件。

    2.2 通过流程定义文件,为特定的流程配置监听器

    标题什么意思的?按照第一种方式,是对与流程引擎中部署的所有流程进行监听,那么也有可能一些监听器只想监听特指的流程定义该怎么做呢?我们可以通过在流程定义xml文件中配置监听器,从而实现监听特定流程。

    • 流程定义文件
    <process id="testEventListeners">
      <extensionElements>
        <activiti:eventListener class="org.activiti.engine.test.MyEventListener" />
        <activiti:eventListener delegateExpression="${testEventListener}" events="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" />
      </extensionElements>
    
      ...
    
    </process>
    

    这里可以通过监听器全类名配置到class属性中,这样就实现了全局监听器,监听该流程定义中所有事件的动作。

    通过events和delegateExpression配合使用指定监听该流程中events中所包含类型的事件的动作。其中delegateExpression中${}中的值为监听器bean的id。

    三、源码分析

    3.1 监听器调用顺序

    从以上代码不难看出,监听器配置在两个地方,一个为全局监听器,监听所有类型事件;一个为指定事件类型监听器,只监听指定类型的事件。那么如果同一个类型事件的监听都配置在了上述两种监听器属性中,那么调用顺序是怎样的呢?

    这里就应该是事件转发器的职责了。查看事件转发器源码:

       protected ActivitiEventSupport eventSupport = new ActivitiEventSupport();
       protected boolean enabled = true;
    
       public void dispatchEvent(ActivitiEvent event) {
           if (this.enabled) {
               this.eventSupport.dispatchEvent(event);
           }
    
           if (event.getType() == ActivitiEventType.ENTITY_DELETED && event instanceof ActivitiEntityEvent) {
               ActivitiEntityEvent entityEvent = (ActivitiEntityEvent)event;
               if (entityEvent.getEntity() instanceof ProcessDefinition) {
                   return;
               }
           }
    
           CommandContext commandContext = Context.getCommandContext();
           if (commandContext != null) {
               BpmnModel bpmnModel = this.extractBpmnModelFromEvent(event);
               if (bpmnModel != null) {
                   ((ActivitiEventSupport)bpmnModel.getEventSupport()).dispatchEvent(event);
               }
           }
    
       }
    

    从这里看到其实转发的任务实际都是由ActivitiEventSupport进行实现。
    查看ActivitiEventSupport源码

        protected List<ActivitiEventListener> eventListeners = new CopyOnWriteArrayList();
        protected Map<ActivitiEventType, List<ActivitiEventListener>> typedListeners = new HashMap();
        public void dispatchEvent(ActivitiEvent event) {
            if (event == null) {
                throw new ActivitiIllegalArgumentException("Event cannot be null.");
            } else if (event.getType() == null) {
                throw new ActivitiIllegalArgumentException("Event type cannot be null.");
            } else {
                if (!this.eventListeners.isEmpty()) {
                    Iterator var2 = this.eventListeners.iterator();
    
                    while(var2.hasNext()) {
                        ActivitiEventListener listener = (ActivitiEventListener)var2.next();
                        this.dispatchEvent(event, listener);
                    }
                }
    
                List<ActivitiEventListener> typed = (List)this.typedListeners.get(event.getType());
                if (typed != null && !typed.isEmpty()) {
                    Iterator var6 = typed.iterator();
    
                    while(var6.hasNext()) {
                        ActivitiEventListener listener = (ActivitiEventListener)var6.next();
                        this.dispatchEvent(event, listener);
                    }
                }
    
            }
        }
    
        protected void dispatchEvent(ActivitiEvent event, ActivitiEventListener listener) {
            try {
                listener.onEvent(event);
            } catch (Throwable var4) {
                if (listener.isFailOnException()) {
                    throw new ActivitiException("Exception while executing event-listener", var4);
                }
    
                LOG.warn("Exception while executing event-listener, which was ignored", var4);
            }
    
        }  
    
    

    ActivitiEventSupport持有全局监听器集合以及指定类型监听器Map,在进行转发时,先对全局监听器集合eventListeners进行遍历转发,再取出指定类型监听器Map中该事件类型的监听器集合进行遍历转发。

    3.2、禁用针对所有流程定义配置的监听器(即通过ProcessEngineConfiguration配置监听器)

    从3.1的ActivitiEventDispatcherImpl中dispatchEvent中可以看出,如果enable属性为true那么则调用ActivitiEventSupport中的dispatcher方法。所有可以通过配置该属性来达到禁用针对所有流程定义配置的监听器。注意:配置为false不会禁用2.2节中为特定流程配置的监听器

    配置实战

        <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
    
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_activiti" />
            <property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
            <property name="jdbcUsername" value="root" />
            <property name="jdbcPassword" value="1234" />
            <property name="databaseSchemaUpdate" value="true" />
            
            <property name="enableEventDispatcher" value="false"/>
            <property name="eventListeners">
                <list>
                    <bean class="char3.MyEventListener"/>
                </list>
            </property>
        </bean>
    

    这样事件转发时就不会触发监听器的onEvent方法。

    四、事件类型

    一直再说事件监听器,那么事件都有哪些类型呢?
    这里官方文档已经详细明确给出所有的事件类型。点击查看事件类型

    到这里就事件监听器就说完啦,有问题或者补充的地方欢迎交流!!!

    timg.jpg

    相关文章

      网友评论

        本文标题:activiti6.0源码剖析之事件处理器(Event Hand

        本文链接:https://www.haomeiwen.com/subject/xtrmbqtx.html