activiti学习(十一)——全局事件监听器的基本使用及其原理

在流程运转的过程中,流程引擎会发出很多不同的事件,前面的文章,我们通过执行监听器和任务监听器捕获到对应事件并进行处理。除了这两个监听器以外,activiti从5.15版开始加入了全局事件监听器,这样很多重复的监听器就不需要在每个活动上去绑定。添加全局监听器有几种方式,包括 通过流程引擎文件方式进行配置、通过流程文档进行配置、动态添加全局事件监听器等方式,下面分别展示这几种方法:

通过流程引擎文件方式进行配置

首先创建全局监听器MyEventListener.java,全局监听器需要实现ActivitiEventListener接口

public class MyEventListener implements ActivitiEventListener{

	public void onEvent(ActivitiEvent event) {
		System.out.println("eventName:" + event.getType().name());
	}

	public boolean isFailOnException() {
		return false;
	}
}

这个监听器,我们只让它把所触发的事件都输出。

接着我们通过流程引擎配置文件进行配置,新建activitiEventListener.cfg.xml:




	

		
		
		
		
		
		
		
		
			
				
			
		
	

17-21行新增自定义的全局事件监听器列表。bpmn图我们使用《activiti学习(二)——activiti流程的部署》的firstBPM.bpmn。然后我们通过初始化流程引擎、部署、启动流程等操作,可以观察全局事件监听器捕捉到的事件类型。

通过流程文档进行配置

在这个例子中,我们使用《activiti学习(一)——activiti流程引擎的配置与初始化操作》的activiti.cfg.xml的配置文件,然后把全局事件监听器添加到流程文档的process元素内,创建eventListenerBPM.bpmn:



	
		
			
		
		
		
		
		
		
	
	
		
			
				
			
			
				
			
			
				
			
			
				
				
			
			
				
				
			
		
	

9-11行通过扩展元素为process添加全局事件监听器。

 

动态添加全局事件监听器

这种方式是利用RuntimeService的addEventListener方法进行监听器的注册。我们使用最简单的firstBPM.bpmn和activiti.cfg.xml,在初始化流程引擎时,我们通过RuntimeService进行添加,之后再部署和执行流程,可观察效果:

	public void getFromProcessEngineConfiguration() {
		ProcessEngineConfiguration pec = ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
		pe = pec.buildProcessEngine();
		RuntimeService rs = pec.getRuntimeService();
		rs.addEventListener(new MyEventListener());
	}

第5行获取RuntimeService,第6行通过addEventListener添加新的全局事件监听器。注意必须在流程引擎创建后才可以通过getRuntimeService获取。

 

事件类型

activiti事件类型非常多,建议大家到其官网查阅:https://www.activiti.org/5.x/userguide/#eventDispatcherEventTypes

 

关闭事件转发器

事件转发器默认打开,如果不想使用全局事件监听器,可以关闭事件转发器,在cfg.xml中配置:



		......
		
		
		
	

关闭事件转发器并不会影响任务监听器和执行监听器的监听,只会影响全局事件监听器。

 

日志监听器

日志监听器本质上也是一个全局事件监听器,主要记录流程实例和任务节点相关的事件和信息,并不会把所有事件都记录。记录的数据在act_evt_log表中。开启的方法是在cfg.xml中配置enableDatabaseEventLogging属性为true

	

        ......
		
		
	

 

具体类型事件监听器

除了eventListeners之外,activiti还可以让用户专门监听指定的事件类型 。看下具体例子,监听器沿用上面的MyEventListener.java,重点是在cfg.xml里对processEngineConfiguration的typedEventListeners属性进行设置:



        ......省略

		
			
				
					
						
					
				
			
		
	

上面我们设定这个监听器只监听“PROCESS_STARTED”事件,即流程开始事件。这样只有当触发PROCESS_STARTED事件才会被改监听器捕获。

 

全局事件监听器原理

全局事件监听器原理的源头——事件转发器。所有事件都是通过事件转发器调用已注册的监听器的onEvent方法实现的。首先我们看看事件转发器的初始化,在ProcessEngineConfigurationImpl.java

protected void init() {
    ......省略

    initFailedJobCommandFactory();
    initEventDispatcher();
    initProcessValidator();

    ......
}

protected 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> 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);
            }
        }
    }
}

第5行initEventDispatcher()开始初始化事件转发器。12-14行若没有配置用户自定义事件转发器,则创建默认事件转发器。16行根据配置设定是否开启事件转发。18-22行根据用户配置的eventListeners属性注册全局事件监听器。24-33行根据用户配置的typedEventListeners属性注册指定事件类型的全局事件监听器。

我们拿流程文档部署命令DeployCmd.java来看事件的具体触发:

  public Deployment execute(CommandContext commandContext) {
  
......
    
    if (commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
	    commandContext.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
	    		ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, deployment));
    }
    
......
    
    if (commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
        commandContext.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
            ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_INITIALIZED, deployment));
    }
    
    return deployment;
  }

上面6-7行触发ENTITY_CREATED事件,13-14行触发ENTITY_INITIALIZED。acitiviti通过ActivitiEventDispatcherImpl的dispatchEvent进行事件转发,查看ActivitiEventDispatcherImpl.java:

public void dispatchEvent(ActivitiEvent event) {
    if (enabled) {
        eventSupport.dispatchEvent(event);
    }

    // Check if a process context is active. If so, we also call the
    // process-definition specific listeners (if any).
    if (Context.isExecutionContextActive()) {
        ProcessDefinitionEntity definition = Context.getExecutionContext().getProcessDefinition();
        if (definition != null) {
            definition.getEventSupport().dispatchEvent(event);
        }
    } else {
        // Try getting hold of the Process definition, based on the process
        // definition-key, if a context is active
        CommandContext commandContext = Context.getCommandContext();
        if (commandContext != null) {
            ProcessDefinitionEntity processDefinition = extractProcessDefinitionEntityFromEvent(event);
            if (processDefinition != null) {
                processDefinition.getEventSupport().dispatchEvent(event);
            }
        }
    }
}

第3行委托ActivitiEventSupport进行事件转发。第8-23行为通过流程定义内部的ActivitiEventSupport进行转发。第8行判断流程实例是否开始运行,如果是则获取流程定义实体,通过流程定义实体内管理的ActivitiEventSupport进行转发。注意这个ActivitiEventSupport和第3行的不同,是流程定义实体内部创建的。这两种转发有什么不同呢?在activiti 5.15之前,只能在流程文档的process元素里面配置全局事件监听器,在流程文档中配置的事件监听器会由流程定义内部的ActivitiEventSupport进行转发。目前的代码设计是新老版本的兼容。之后我们跟踪ActivitiEventSupport.java看其如何转发:

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 typed = typedListeners.get(event.getType());
    if (typed != null && !typed.isEmpty()) {
        for (ActivitiEventListener listener : typed) {
            dispatchEvent(event, listener);
        }
    }
}

protected void dispatchEvent(ActivitiEvent event, ActivitiEventListener listener) {
    try {
	    listener.onEvent(event);
    } catch (Throwable t) {
        if (listener.isFailOnException()) {
            throw new ActivitiException("Exception while executing event-listener", t);
        } else {
            LOG.warn("Exception while executing event-listener, which was ignored", t);
        }
    }
}

11-13行获取注册的全局事件监听器并逐个转发,16-21行则根据事件类型获取注册的指定类型全局监听器并转发。26行调用监听器的onEvent方法。

你可能感兴趣的:(Activiti)