activiti学习笔记(六) 监听器

activiti全局监听器

全局监听器主要使用的场景就是监控这个流程的启动和结束。流程开始的时候可以监控,流程结束的时候也可以监控

监听器的接口

public interface ActivitiEventListener {

  /**当时间被执行时调用该方法*/
  void onEvent(ActivitiEvent event);

 /**
  * @author 郑小康
  * 这个是onEvent执行失败之后进行的处理
  *
  * 如果是true则返回onEvent执行失败的异常
  *
  * 如果是false则忽略这个异常
  * */
  boolean isFailOnException();
}

初始化所有监听器

将所有全局监听器和类型监听器给加入到当前eventListeners里面,这里只是初始化过程

/**
   * @author 郑小康
   *
   * 事件监听器分为两种
   *
   * 1.如果eventDispatcher为空,则实例化ActivitiEventDispatcherImpl
   *
   * 2.设置eventDispatcher的状态为enableEventDispatcher,其值为true 默认支持事件转发
   *
   * 3.遍历当前流程实例所有的eventListeners监听器,将其添加到eventDispatcher
   *
   * 4.遍历所有typedEventListeners 以entry为key进行添加
   *   在cfg.xml文件定义:
   *    <property name="typedEventListeners">
   *      <map>
   *           <entry key="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" >
   *               <list>
   *                  <bean class="org.activiti.engine.example.MyJobEventListener" />
   *                </list>
   *           </entry>
   *     </map>
   *   </property>
   * */
  public void initEventDispatcher() {
    if (this.eventDispatcher == null) {
      this.eventDispatcher = new ActivitiEventDispatcherImpl();
    }

    this.eventDispatcher.setEnabled(enableEventDispatcher);

    if (eventListeners != null) {
      for (ActivitiEventListener listenerToAdd : eventListeners) {
        this.eventDispatcher.addEventListener(listenerToAdd);
      }
    }

    if (typedEventListeners != null) {
      for (Entry<String, List<ActivitiEventListener>> listenersToAdd : typedEventListeners.entrySet()) {
        // Extract types from the given string
        ActivitiEventType[] types = ActivitiEventType.getTypesFromString(listenersToAdd.getKey());

        for (ActivitiEventListener listenerToAdd : listenersToAdd.getValue()) {
          this.eventDispatcher.addEventListener(listenerToAdd, types);
        }
      }
    }

  }

初始化监听器配置过程

   其实在流程实例中注入相对应的属性bean

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="driverClassName">
			<value>com.mysql.jdbc.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://127.0.0.1:3306/activiti?useUnicode=true&characterEncoding=UTF-8
			</value>
		</property>
		<property name="username">
			<value>root</value>
		</property>
		<property name="password" value="fadp" />
	</bean>

	<bean id="processEngine1" name="processEngineConfiguration"
		class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<property name="dataSource" ref="dataSource" />
		<property name="databaseSchemaUpdate" value="true" />
		<property name="eventListeners">
			<list>
				<bean class="com.event.MyEventListener" />
			</list>
		</property>
	</bean>

</beans>

监听器在流程实例启动时候的应用

       在构建流程实例的时候,会构建一个流程实例,在器最后会构建一个引擎启动时间,调用所有监听器的onEvent 方法

public ProcessEngineImpl(ProcessEngineConfigurationImpl processEngineConfiguration) {
     .......
    //调用时间转发器,构建一个事件实例ActivitiEvent类型为ENGINE_CREATED,然后进行事件转发
    processEngineConfiguration.getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createGlobalEvent(ActivitiEventType.ENGINE_CREATED));
  }
/**
   * 1.enabled判断,默认为true进行事件转发
   *
   * 2.FIXME:尚未理解
   * */
  @Override
  public void dispatchEvent(ActivitiEvent event) {
    if (enabled) {
      eventSupport.dispatchEvent(event);
    }

    if (event.getType() == ActivitiEventType.ENTITY_DELETED && event instanceof ActivitiEntityEvent) {
      ActivitiEntityEvent entityEvent = (ActivitiEntityEvent) event;
      if (entityEvent.getEntity() instanceof ProcessDefinition) {
        // process definition deleted event doesn't need to be dispatched to event listeners
        return;
      }
    }
    

    CommandContext commandContext = Context.getCommandContext();
    if (commandContext != null) {
      BpmnModel bpmnModel = extractBpmnModelFromEvent(event);
      if (bpmnModel != null) {
        ((ActivitiEventSupport) bpmnModel.getEventSupport()).dispatchEvent(event);
      }
    }
    
  }
 /**
   * @author  郑小康
   *
   * 1.对当前转化的事件做非空校验
   *
   * 2.转化所有全局事件监听器
   *
   * 3.获取跟当前事件类型相同的事件监听器,并进行事件转化进行执行
   *
   * */
  public void dispatchEvent(ActivitiEvent event) {
    if (event == null) {
      throw new ActivitiIllegalArgumentException("Event cannot be null.");
    }

    if (event.getType() == null) {
      throw new ActivitiIllegalArgumentException("Event type cannot be null.");
    }

    //执行所有全局事件监听器
    if (!eventListeners.isEmpty()) {
      for (ActivitiEventListener listener : eventListeners) {
        dispatchEvent(event, listener);
      }
    }

    //获取跟当前事件类型相同的事件监听器,并进行事件转化进行执行
    List<ActivitiEventListener> typed = typedListeners.get(event.getType());
    if (typed != null && !typed.isEmpty()) {
      for (ActivitiEventListener listener : typed) {
        dispatchEvent(event, listener);
      }
    }
  }

测试

        @Test
	public void getDefaultProcessEngine() {
		ProcessEngineConfiguration pec = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("com/event/activiti.cfg.xml");
		ProcessEngine pe1 = pec.buildProcessEngine();
	}

测试结果

Event received: ENGINE_CREATED

       其中还有一种动态加载监听器的过程,通过第一个流程实例获取监听器的集合,进行添加,在第二个流程实例中就可以这样用了,为什么是这样呢,因为spring获取bean是单例模式,监听器引用类型指向的是同一个变量,使用过程如下:

        @Before
	public void init() {
		processEngine = ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource(
						"com/activiti_study/ch24/activiti1.cfg.xml")
				.buildProcessEngine();
		repositoryService = processEngine.getRepositoryService();
		activitiEventDispatcher = ((ProcessEngineConfigurationImpl) processEngine
				.getProcessEngineConfiguration()).getEventDispatcher();
	}
        @Test
	public void testAddEventListener() {
		ShareniuTaskEventListener2 shareniuTaskEventListener2 = new ShareniuTaskEventListener2();
		activitiEventDispatcher.addEventListener(shareniuTaskEventListener2);
		ProcessEngine pe = ProcessEngines.getDefaultProcessEngine();
		System.out.println(pe);

		processEngine = ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource(
						"com/activiti_study/ch24/activiti1.cfg.xml")
				.buildProcessEngine();
	}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏牛肉圆粉不加葱

Spark Storage ④ - 存储执行类介绍(DiskBlockManager、DiskStore、MemoryStore)

这篇文章前半部分我们对直接在 Block 存取发挥重要作用的类进行介绍,主要是 DiskBlockManager、MemoryStore、DiskStore。后...

632
来自专栏大内老A

[WCF REST] Web消息主体风格(Message Body Style)

对于Web HTTP编程模型来说,服务契约中作为操作的方法无须应用OperationContractAttribute特性,只需要根据需要应用WebGetAtt...

1749
来自专栏技术博客

C#多线程

根据上一节中http://www.cnblogs.com/aehyok/archive/2013/05/02/3054615.html对多线程的入门了解。本节就...

572
来自专栏ShaoYL

内存管理总结-autoreleasePool

3206
来自专栏偏前端工程师的驿站

前端魔法堂——异常不仅仅是try/catch

1103
来自专栏JavaQ

高并发编程-CAS深入解析

CAS(Compare and swap)直译过来就是比较和替换,是一种通过硬件实现并发安全的常用技术,底层通过利用CPU的CAS指令对缓存加锁或总线加锁的方式...

561
来自专栏三丰SanFeng

扩展mysql - 手把手教你写udf

使用过MySQL的人都知道,MySQL有很多内置函数提供给使用者,包括字符串函数、数值函数、日期和时间函数等,给开发人员和使用者带来了很多方便。

2815
来自专栏哲学驱动设计

Rafy 框架 - 通用查询条件(CommonQueryCriteria)

在应用开发过程中,有 80% 的场景下,开发者所需要的实体查询,查询条件中其实都是一些简单的属性匹配,又或是一些属性匹配的简单组合。Rafy 为这样的场景提供了...

1977
来自专栏更流畅、简洁的软件开发方式

分页控件和几个相关控件的源代码

分页控件的源代码,可能会让有些人失望,因为代码很乱。乱的一个原因呢,可能是没有采用OO的思路吧,因为写控件的时候还一点都不会OO呢,只是一直在用,也就没有作大的...

1955
来自专栏移动端开发

iOS 多线程之线程锁Swift-Demo示例总结

线程锁是什么       在前面的文章中总结过多线程,总结了多线程之后,线程锁也是必须要好好总结的东西,这篇文章构思的时候可能写的东西得许多,只能挤时间一点点的...

3457

扫描关注云+社区