從5.17.0版本的activiti開始提供作業執行者(Job Executor)和異步作業執行者(Async Executor),Async Executor執行表現更好,並且執行異步作業對數據庫更加友善。activiti官方推薦使用Async Executor,並且一些老的Job Executor依舊有效。在Java EE 7運行環境中,JSR-236規范支持容器管理ManagedJobExecutor和ManagedAsyncJobExecutor,例如可以配置如下:
<bean id="threadFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="java:jboss/ee/concurrency/factory/default" /> </bean> <bean id="customJobExecutor" class="org.activiti.engine.impl.jobexecutor.ManagedJobExecutor"> <!-- ... --> <property name="threadFactory" ref="threadFactory" /> <!-- ... --> </bean>
Job executor作為管理多線程執行定時任務的組件,在單元測試場景裡,Job executor在多線程中執行是測試不方便的,所以activiti提供了api解決了這個麻煩:
查詢獲取Job executor可以通過ManagementService.createJobQuery方法實現,執行該作業可以調用ManagementService.executeJob,使得在單元測試中Job executor可以被控制,順利關閉Job executor。默認的Job executor是在流程引擎啟動就被激活的,如果需要關閉這個功能,可以配置:
<property name="jobExecutorActivate" value="false" />
AsyncExecutor作為管理線程池執行定時任務的組件,默認activiti是關閉AsyncExecutor的,使用它的配置如下:
<property name="asyncExecutorEnabled" value="true" /> <property name="asyncExecutorActivate" value="true" />
asyncExecutorEnabled屬性設置設置true後將代替那些老的Job executor,第二個屬性asyncExecutorActivate是指示activiti在流程引擎啟動就激活AsyncExecutor。
所有被解析的流程定義都會被緩存起來,這是因為流程定義是不會改變的,沒有必要多次請求數據庫。默認的activiti是沒有限制緩存數量的,如果需要設置:
<property name="processDefinitionCacheLimit" value="10" />
緩存內部是使用HashMap數據結構和LRU算法實現的。當然,緩存的數量的設置值最好根據流程定義的總數和正在運行的流程實例使用的流程定義數量決定。你也可以使用自定義的緩存實現類替換內部提供的緩存實現,只需要實現接口org.activiti.engine.impl.persistence.deploy.DeploymentCache,然後配置即可:
<property name="processDefinitionCache"> <bean class="org.activiti.MyCache" /> </property>
對於自定義緩存實現的緩存數量限制可以設置knowledgeBaseCacheLimit和knowledgeBaseCache屬性。
在activiti 5.12的時候,日志框架使用的是SLF4J,替換掉早前的jdk的日志工具,現在所有的日志(activiti, spring, mybatis, …)都通過SLF4J來輸出日志,你可以具體的日志實現。
工作流沒有提供日志的具體實現jar包在依賴裡面,需要你自己手動添加,如果沒有添加,SLF4J會全程使用NOP-logger,它不會全程記錄所有的日志的,並且警告沒有被記錄,在Maven中比如添加log4j:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency>
activiti-explorer和activiti-rest項目是使用的log4j,activiti項目測試也是使用的log4j記錄日志。
如果你的類路徑下面已經有了commons-logging的jar了的話,這時需要commons-logging干的活交給slf4j,比如要讓spring輸出日志使用slf4j的話,需要使用依賴:
<dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> </dependency>
如果使用的服務器是Tomcat,需要注意tomcat自己的類路徑下面也有日志的jar包,解決辦法參考:http://www.slf4j.org/codes.html#release
從版本5.13開始,Activiti支持使用slf4j記錄工作流上下文,日志通過底層日志logger記錄的內容有:
processDefinition Id ------ mdcProcessDefinitionID
processInstance Id ------- mdcProcessInstanceID
execution Id - ---- mdcexecutionId
日志記錄有格式化的信息和其他的普通信息,例如日志記錄可以配置:
log4j.appender.consoleAppender.layout.ConversionPattern =ProcessDefinitionId=%X{mdcProcessDefinitionID} executionId=%X{mdcExecutionId} mdcProcessInstanceID=%X{mdcProcessInstanceID} mdcBusinessKey=%X{mdcBusinessKey} %m%n"在系統關鍵的地方進行記錄或檢測是非常有必要的,通過日志分析也是其中一種手段。
在Activiti 5.15中引入了事件機制,它讓你在工作流引擎中的各種事件發生時得到消息,activiti能夠支持注冊一個偵聽器對於某些類型的事件而不是任何類型的事件發生時收到通知,一方面可以在配置文件中添加engine-wide事件監聽器配置,然後engine-wide事件監聽器類會調用相應的API,另一方面也可以在在BPMN配置文件中配置。
所有的事件類都是org.activiti.engine.delegate.event.ActivitiEvent的子類,事件會提供type、executionId、processInstanceId和processDefinitionId,某些事件包含了事件發生的上下文,附加載荷的信息。
事件監聽器需要實現org.activiti.engine.delegate.event.ActivitiEventListener,例如:
public class MyEventListener implements ActivitiEventListener { @Override public void onEvent(ActivitiEvent event) { switch (event.getType()) { case JOB_EXECUTION_SUCCESS: System.out.println("A job well done!"); break; case JOB_EXECUTION_FAILURE: System.out.println("A job has failed..."); break; default: System.out.println("Event received: " + event.getType()); } } @Override public boolean isFailOnException() { // The logic in the onEvent method of this listener is not critical, exceptions // can be ignored if logging fails... return false; } }
MyEventListener接收標准事件類型並處理和異常處理,其中isFailOnException()決定了onEvent(..)是否拋出異常,如果返回false,異常將會被忽略。如果返回true,異常將會逐級向上提交,
造成當前運行的命令的失敗。如果當前執行具有事務,事務將會回滾。activiti官方建議如果事件的業務不是非常重要,還是返回false。
activiti提供了通用的實現類來處理普通的事件監聽,例如:
org.activiti.engine.delegate.event.BaseEntityEventListener:它將會監聽entity類的事件,它隱藏了類型檢查和重寫了四個方法,onCreate(..), onUpdate(..)和onDelete(..),
對於其他的事件,onEntityEvent(..)將會被調用。
2.9 事件的相關配置
如果一個事件監聽器在流程引擎配置,流程引擎啟動將會激活,即使重啟引擎也會保持該狀態。eventListeners屬性值為org.activiti.engine.delegate.event.ActivitiEventListener
的實例的list,例如:
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> ... <property name="eventListeners"> <list> <bean class="org.activiti.engine.example.MyEventListener" /> </list> </property> </bean>
另外typedEventListeners屬性值為Map,key為事件的名稱,value表示為一個org.activiti.engine.delegate.event.ActivitiEventListener的list集合,例如:
<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="org.activiti.engine.example.MyJobEventListener" /> </list> </entry> </map> </property> </bean>
事件發生的順序取決於被配置的監聽器的順序。首先,所有的普通的監聽器會被調用(也就是說eventListeners屬性,至於eventListeners的內部的監聽器順序和配置的順序有關)
,然後是在typedListeners屬性配置的會被調用。
調用RuntimeService的api方法可以實現這個功能:(注意:系統重啟會導致監聽器消失)
void addEventListener(ActivitiEventListener listenerToAdd); void addEventListener(ActivitiEventListener listenerToAdd, ActivitiEventType... types); void removeEventListener(ActivitiEventListener listenerToRemove);
在流程定義中添加監聽器是允許的,這裡定義的監聽器會被流程定義相關的事件和所有的相關的流程實例啟動後調用,監聽器的實現類可以使用全類名、能夠被解析為bean的表達式。例如下面這個配置,第一個監聽器將接收所有的事件,它使用的是全類名進行配置的,第二個監聽器僅僅是在作業執行成功或者失敗會被執行,並且使用了在流程引擎中定義的beans屬性配置的監聽器的表達式。
<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>
如果我們需要在流程定義中配置監聽entity的監聽器的話,可以這樣配置:
<process id="testEventListeners"> <extensionElements> <activiti:eventListener class="org.activiti.engine.test.MyEventListener" entityType="task" /> <activiti:eventListener delegateExpression="${testEventListener}" events="ENTITY_CREATED" entityType="task" /> </extensionElements> ... </process>
其中entityType的值有:attachment, comment, execution, identity-link, job, process-instance, process-definition, task。