activiti工作流

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

2019-04-01  本文已影响13人  我有一只喵喵

前言

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

在介绍如何使用以及原理之前先介绍贯穿整个事件机制的三个元素。

接下来走进实战


一、实现监听器

实现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有两个事件监听器属性:

<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
    ...
    <property name="eventListeners">
      <list>
         <bean class="cn.cf.MyEventListener" />
      </list>
    </property>
</bean>
<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添加事件监听器。除了这种方式,我们还可以在运行时动态添加监听器。但是此种方法在流程引擎重启之后就会消失。

   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
上一篇 下一篇

猜你喜欢

热点阅读