工作流引擎詳解!工作流開源框架ACtiviti的詳細配置以及安裝和使用


創建ProcessEngine

  • Activiti流程引擎的配置文件是名為activiti.cfg.xml的XML文件.注意與使用Spring方式創建流程引擎是不一樣的
  • 使用org.activiti.engine.ProcessEngines類,獲得ProcessEngine:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine()

它會在classpath下搜索activiti.cfg.xml,並基於這個文件中的配置構建引擎

<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="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

    <property name="jdbcUrl" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
    <property name="jdbcDriver" value="org.h2.Driver" />
    <property name="jdbcUsername" value="sa" />
    <property name="jdbcPassword" value="" />

    <property name="databaseSchemaUpdate" value="true" />

    <property name="jobExecutorActivate" value="false" />

    <property name="mailServerHost" value="mail.my-corp.com" />
    <property name="mailServerPort" value="5025" />
  </bean>

</beans>

配置文件中使用的ProcessEngineConfiguration可以通過編程方式創建,可以配置不同的bean id

ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String resource);
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String resource, String beanName);	// 配置不同的bean id
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(InputStream inputStream);
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName);

如果不使用配置文件進行配置,就會基於默認創建配置

  • ProcessEngineConfiguration.createXXX() 方法都會返回ProcessEngineConfiguration,后續可以調整成所需的對象. 在調用buildProcessEngine()后, 就會創建一個ProcessEngine:
  ProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()
  .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE)
  .setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000")
  .setJobExecutorActivate(true)
  .buildProcessEngine();

ProcessEngineConfiguration bean

  • activiti.cfg.xml必須包含一個id='processEngineConfiguration' 的bean
 <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

這個bean會用來構建ProcessEngine. 有多個類可以用來定義processEngineConfiguration. 這些類對應不同的環境,並設置了對應的默認值:

  • org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration: 單獨運行的流程引擎.Activiti會自己處理事務.默認數據庫只在引擎啟動時檢測(如果沒有Activiti的表或者表結構不正確就會拋出異常)
  • org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration: 單元測試時的輔助類.Activiti會自己控制事務. 默認使用H2內存數據庫,數據庫表會在引擎啟動時創建,關閉時刪除.使用它時,不需要其他配置(除非使用job執行器或郵件功能)
  • org.activiti.spring.SpringProcessEngineConfiguration: 在Spring環境下使用流程引擎
  • org.activiti.engine.impl.cfg.JtaProcessEngineConfiguration: 單獨運行流程引擎,並使用JTA事務

數據庫配置

定義數據庫配置參數

  • 基於數據庫配置參數定義數據庫連接配置
    • jdbcUrl: 數據庫的JDBC URL
    • jdbcDriver: 對應不同數據庫類型的驅動
    • jdbcUsername: 連接數據庫的用戶名
    • jdbcPassword: 連接數據庫的密碼
  • 基於JDBC參數配置的數據庫連接 會使用默認的MyBatis連接池,配置MyBatis連接池:
    • jdbcMaxActiveConnections: 連接池中處於被使用狀態的連接的最大值.默認為10
    • jdbcMaxIdleConnections: 連接池中處於空閑狀態的連接的最大值
    • jdbcMaxCheckoutTime: 連接被取出使用的最長時間,超過時間會被強制回收. 默認為20000(20秒)
    • jdbcMaxWaitTime: 這是一個底層配置,讓連接池可以在長時間無法獲得連接時, 打印一條日志,並重新嘗試獲取一個連接.(避免因為錯誤配置導致沉默的操作失敗) 默認為20000(20秒)

使用javax.sql.DataSource配置

  • Activiti的發布包中沒有這些類, 要把對應的類放到classpath下
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" >
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="jdbc:mysql://localhost:3306/activiti" />
  <property name="username" value="activiti" />
  <property name="password" value="activiti" />
  <property name="defaultAutoCommit" value="false" />
</bean>

<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

    <property name="dataSource" ref="dataSource" />
    ...
</bean>
  • 無論使用JDBC還是DataSource,都可以設置下面的配置:
    • databaseType:
      • 一般不用設置,因為可以自動通過數據庫連接的元數據獲取
      • 只有自動檢測失敗時才需要設置.可能的值有:
      • 如果沒使用默認的H2數據庫就必須設置這項.這個配置會決定使用哪些創建/刪除腳本和查詢語句
    • databaseSchemaUpdate: 設置流程引擎啟動和關閉時如何處理數據庫表
      • false:默認, 檢查數據庫表的版本和依賴庫的版本,如果版本不匹配就拋出異常
      • true: 構建流程引擎時,執行檢查,如果需要就執行更新. 如果表不存在,就創建
      • create-drop: 構建流程引擎時創建數據庫表,關閉流程引擎時刪除這些表

JNDI數據庫配置

  • 在默認情況下,Activiti的數據庫配置會放在web應用的WEB-INF/classes目錄下的db.properties文件中. 這樣做比較繁瑣,因為要用戶在每次發布時,都修改Activiti源碼中的db.properties並重新編譯war文件,或者解壓縮war文件,修改其中的db.properties
  • 使用 JNDI(Java命名和目錄接口) 來獲取數據庫連接,連接是由servlet容器管理的,可以在war部署外邊管理配置. 與db.properties相比,它也允許對連接進行更多的配置

JNDI的使用

  • Activiti Explorer和Activiti Rest應用從db.properties轉換為使用JNDI數據庫配置:
    • 需要打開原始的Spring配置文件:
      • activiti-webapp-explorer/src/main/webapp/WEB-INF/activiti-standalone-context.xml
      • activiti-webapp-rest2/src/main/resources/activiti-context.xml
    • 刪除dbPropertiesdataSource兩個bean,然后添加如下bean:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/activitiDB"/>
</bean>
  • 我們需要添加包含了默認的H2配置的context.xml文件
  • 如果已經有了JNDI配置,會覆蓋這些配置.對應的配置文件activiti-webapp-explorer2/src/main/webapp/META-INF/context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/activiti-explorer2">
    <Resource auth="Container"
              name="jdbc/activitiDB"
              type="javax.sql.DataSource"
              scope="Shareable"
              description="JDBC DataSource"
              url="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000"
              driverClassName="org.h2.Driver"
              username="sa"
              password=""
              defaultAutoCommit="false"
              initialSize="5"
              maxWait="5000"
              maxActive="120"
              maxIdle="5"/>
</Context>
  • 如果是Activiti REST應用,則添加activiti-webapp-rest2/src/main/webapp/META-INF/context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/activiti-rest2">
    <Resource auth="Container"
              name="jdbc/activitiDB"
              type="javax.sql.DataSource"
              scope="Shareable"
              description="JDBC DataSource"
              url="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=-1"
              driverClassName="org.h2.Driver"
              username="sa"
              password=""
              defaultAutoCommit="false"
              initialSize="5"
              maxWait="5000"
              maxActive="120"
              maxIdle="5"/>
</Context>
  • 最后刪除Activiti Explorer和Activiti Rest兩個應用中不再使用的db.properties文件

JNDI的配置

  • JNDI數據庫配置會因為使用的Servlet container不同而不同
  • Tomcat容器中的JNDI配置如下:
    • JNDI資源配置在CATALINA_BASE/conf/[enginename]/[hostname]/[warname].xml(對於Activiti Explorer來說,通常是在CATALINA_BASE/conf/Catalina/localhost/activiti-explorer.war) 當應用第一次發布時,會把這個文件從war中復制出來.所以如果這個文件已經存在了,需要替換它.修改JNDI資源讓應用連接mysql而不是H2:
<?xml version="1.0" encoding="UTF-8"?>
    <Context antiJARLocking="true" path="/activiti-explorer2">
        <Resource auth="Container"
            name="jdbc/activitiDB"
            type="javax.sql.DataSource"
            description="JDBC DataSource"
            url="jdbc:mysql://localhost:3306/activiti"
            driverClassName="com.mysql.jdbc.Driver"
            username="sa"
            password=""
            defaultAutoCommit="false"
            initialSize="5"
            maxWait="5000"
            maxActive="120"
            maxIdle="5"/>
    </Context>

Activiti支持的數據庫

  • h2: 默認配置的數據庫
  • mysql
  • oracle
  • postgres
  • db2
  • mssql

創建數據庫表

  • 創建數據庫表的方法:
    • activiti-engine的jar放到classpath下
    • 添加對應的數據庫驅動
    • 把Activiti配置文件(activiti.cfg.xml)放到classpath下,指向你的數據庫
    • 執行DbSchemaCreate類的main方法
SQL DDL語句可以從Activiti下載頁或Activiti發布目錄里找到,在database子目錄下.
腳本也包含在引擎的jar中:activiti-engine-x.jar在org/activiti/db/create包下,drop目錄里是刪除語句

- SQL文件的命名方式如下:
[activiti.{db}.{create|drop}.{type}.sql]
type 是:
- engine:引擎執行的表,必須
- identity:包含用戶,群組,用戶與組之間的關系的表.這些表是可選的,只有使用引擎自帶的默認身份管理時才需要
- history:包含歷史和審計信息的表,可選的.歷史級別設為none時不會使用. 注意這也會引用一些需要把數據保存到歷史表中的功能

數據庫表名理解

  • Activiti的表都以ACT_開頭, 第二部分是表示表的用途的兩個字母標識.用途和服務的API對應
    • ACT_RE_*: RE表示repository. 這個前綴的表包含了流程定義和流程靜態資源
    • ACT_RU_*: RU表示runtime. 這些是運行時的表,包含流程實例,任務,變量,異步任務等運行中的數據. Activiti只在流程實例執行過程中保存這些數據, 在流程結束時就會刪除這些記錄.這樣運行時表可以一直很小速度很快
    • ACT_ID_*: ID 表示identity. 這些表包含身份信息. 比如用戶,組等等
    • ACT_HI_*: HI 表示history. 這些表包含歷史數據. 比如歷史流程實例, 變量,任務等等
    • ACT_GE_*: 通用數據. 用於不同場景下

數據庫升級

  • 在執行更新之前要先使用數據庫的備份功能備份數據庫
  • 默認情況下,每次構建流程引擎時都會進行版本檢測.這一切都在應用啟動或Activiti webapp啟動時發生.如果Activiti發現數據庫表的版本與依賴庫的版本不同,就會拋出異常
  • 對activiti.cfg.xml配置文件進行配置來升級:
<beans ... >

  <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
    <!-- ... -->
    <property name="databaseSchemaUpdate" value="true" />
    <!-- ... -->
  </bean>

</beans>
  • 然后,把對應的數據庫驅動放到classpath里.升級應用的Activiti依賴,啟動一個新版本的Activiti指向包含舊版本的數據庫,將databaseSchemaUpdate設置為true,Activiti會自動將數據庫表升級到新版本
  • 當發現依賴和數據庫表版本不通過時,也可以執行更新升級DDL語句
  • 也可以執行數據庫腳本,可以在Activiti下載頁找到

啟用Job執行器

  • JobExecutor是管理一系列線程的組件,可以觸發定時器(包含后續的異步消息).
  • 在單元測試場景下,很難使用多線程.因此API允許查詢Job(ManagementService.createJobQuery)執行Job (ManagementService.executeJob),
  • 因此Job可以在單元測試中控制, 要避免與job執行器沖突,可以關閉它
  • 默認,JobExecutor在流程引擎啟動時就會激活. 如果不想在流程引擎啟動后自動激活JobExecutor,可以設置
<property name="jobExecutorActivate" value="false" />

配置郵件服務器

  • Activiti支持在業務流程中發送郵件,可以在配置中配置郵件服務器
  • 配置SMTP郵件服務器來發送郵件

配置歷史存儲

  • Activiti可以配置來定制歷史存儲信息
<property name="history" value="audit" />

表達式和腳本暴露配置

  • 默認情況下,activiti.cfg.xml和Spring配置文件中所有bean 都可以在表達式和腳本中使用
  • 如果要限制配置文件中的bean的可見性,可以通過配置流程引擎配置的beans來配置
  • ProcessEngineConfiguration的beans是一個map.當指定了這個參數,只有包含這個map中的bean可以在表達式和腳本中使用.通過在map中指定的名稱來決定暴露的bean

配置部署緩存

  • 因為流程定義的數據是不會改變的,為了避免每次使用訪問數據庫,所有流程定義在解析之后都會被緩存
  • 默認情況下,不會限制這個緩存.如果想限制流程定義緩存,可以添加如下配置
<property name="processDefinitionCacheLimit" value="10" />

這個配置會把默認的HashMap緩存替換成LRU緩存來提供限制. 這個配置的最佳值跟流程定義的總數有關,實際使用中會具體使用多少流程定義也有關

  • 也可以注入自定義的緩存實現,這個bean必須實現org.activiti.engine.impl.persistence.deploy.DeploymentCache接口
<property name="processDefinitionCache">
  <bean class="org.activiti.MyCache" />
</property>
  • 類似的配置有knowledgeBaseCacheLimitknowledgeBaseCache, 它們是配置規則緩存的.只有流程中使用規則任務時才用

日志

  • 從Activiti 5.12開始,所有日志(activiti,spring,,mybatis等等)都轉發給slf4j允許自定義日志實現
  • 引入Maven依賴log4j實現,需要添加版本
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
</dependency>
  • 使用Maven的實例,忽略版本
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jcl-over-slf4j</artifactId>
</dependency>

映射診斷上下文

  • Activiti支持slf4j的MDC功能, 如下的基礎信息會傳遞到日志中記錄:
    • 流程定義ID: mdcProcessDefinitionID
    • 流程實例ID: mdcProcessInstanceID
    • 分支ID: mdcexecutionId
  • 默認不會記錄這些信息,可以配置日志使用期望的格式來顯示它們,擴展通常的日志信息. 比如,通過log4j配置定義會讓日志顯示上面的信息:
 log4j.appender.consoleAppender.layout.ConversionPattern =ProcessDefinitionId=%X{mdcProcessDefinitionID}
executionId=%X{mdcExecutionId}mdcProcessInstanceID=%X{mdcProcessInstanceID} mdcBusinessKey=%X{mdcBusinessKey} %m%n"

當系統進行高風險任務,日志必須嚴格檢查時,這個功能就非常有用,要使用日志分析的情況

事件處理

  • Activiti中實現了一種事件機制,它允許在引擎觸發事件時獲得提醒
  • 為對應的事件類型注冊監聽器,在這個類型的任何時間觸發時都會收到提醒:
    • 可以添加引擎范圍的事件監聽器,可以通過配置添加引擎范圍的事件監聽器在運行階段使用API
    • 添加event-listener到特定流程定義的BPMN XML中
  • 所有分發的事件,都是org.activiti.engine.delegate.event.ActivitiEvent的子類.事件包含type,executionId,processInstanceId和processDefinitionId. 對應的事件會包含事件發生時對應上下文的額外信息

事件監聽器實現

  • 實現事件監聽器要實現org.activiti.engine.delegate.event.ActivitiEventListener.
  • 下面監聽器的實現會把所有監聽到的事件打印到標准輸出中,包括job執行的事件異常:
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;
  }
}

isFailOnException(): 決定了當事件分發時onEvent(..) 方法拋出異常時的行為

  • 返回false,會忽略異常
  • 返回true,異常不會忽略,繼續向上傳播,迅速導致當前命令失敗
  • 當事件是一個API調用的一部分時(或其他事務性操作,比如job執行), 事務就會回滾
  • 當事件監聽器中的行為不是業務性時,建議返回false
  • activiti提供了一些基礎的實現,實現了事件監聽器的常用場景可以用來作為基類或監聽器實現的樣例
    • org.activiti.engine.delegate.event.BaseEntityEventListener:
      • 這個事件監聽器的基類可以用來監聽實體相關的事件,可以針對某一類型實體,也可以是全部實體
      • 隱藏了類型檢測,並提供了三個需要重寫的方法:
        • onCreate(..)
        • onUpdate(..)
        • onDelete(..)
        • 當實體創建,更新,或刪除時調用
      • 對於其他實體相關的事件,會調用onEntityEvent(..)

事件監聽器的配置安裝

  • 把事件監聽器配置到流程引擎配置中,會在流程引擎啟動時激活,並在引擎啟動過程中持續工作
  • eventListeners屬性需要org.activiti.engine.delegate.event.ActivitiEventListener的隊列
    • 通常,我們可以聲明一個內部的bean定義,或使用ref引用已定義的bean.下面的代碼,向配置添加了一個事件監聽器,任何事件觸發時都會提醒它,無論事件是什么類型:
<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參數
    • map的key是逗號分隔的事件名或單獨的事件名
    • map的value是org.activiti.engine.delegate.event.ActivitiEventListener隊列
  • 下面的代碼演示了向配置中添加一個事件監聽器,可以監聽job執行成功或失敗:
<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屬性),按照它們在list中的次序
  • 然后,會調用所有對應類型的監聽器(typedEventListeners屬性),對應類型的事件被觸發

運行階段添加監聽器

  • 通過API:RuntimeService, 在運行階段添加或刪除額外的事件監聽器:
/**
 * Adds an event-listener which will be notified of ALL events by the dispatcher.
 * @param listenerToAdd the listener to add
 */
void addEventListener(ActivitiEventListener listenerToAdd);

/**
 * Adds an event-listener which will only be notified when an event occurs, which type is in the given types.
 * @param listenerToAdd the listener to add
 * @param types types of events the listener should be notified for
 */
void addEventListener(ActivitiEventListener listenerToAdd, ActivitiEventType... types);

/**
 * Removes the given listener from this dispatcher. The listener will no longer be notified,
 * regardless of the type(s) it was registered for in the first place.
 * @param listenerToRemove listener to remove
 */
 void removeEventListener(ActivitiEventListener listenerToRemove);
  • 運行階段添加的監聽器引擎重啟后就消失

流程定義添加監聽器

  • 特定流程定義添加監聽器:
    • 監聽器只會監聽與這個流程定義相關的事件以及這個流程定義上發起的所有流程實例的事件
  • 監聽器實現:
    • 可以使用全類名定義
    • 引用實現了監聽器接口的表達式
    • 配置為拋出一個message,signal,errorBPMN事件
監聽器執行自定義邏輯
  • 下面代碼為一個流程定義添加了兩個監聽器:
    • 第一個監聽器會接收所有類型的事件,它是通過全類名定義的
    • 第二個監聽器只接收作業成功或失敗的事件,它使用了定義在流程引擎配置中的beans屬性中的一個bean
<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>
  • 對於實體相關的事件,也可以設置為針對某個流程定義的監聽器,實現只監聽發生在某個流程定義上的某個類型實體事件.下面的代碼演示了如何實現這種功能:
    • 第一個例子:用於監聽所有實體事件
    • 第二個例子:用於監聽特定類型的事件
<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
監聽拋出BPMN事件
  • 另一種處理事件的方法是拋出一個BPMN事件:
    • 只針對與拋出一個activiti事件類型的BPMN事件, 拋出一個BPMN事件,在流程實例刪除時,會導致一個錯誤
  • 下面的代碼演示了如何在流程實例中拋出一個signal,把signal拋出到外部流程(全局),在流程實例中拋出一個消息事件,在流程實例中拋出一個錯誤事件.除了使用classdelegateExpression, 還使用了throwEvent屬性,通過額外屬性,指定了拋出事件的類型
<process id="testEventListeners">
  <extensionElements>
    <activiti:eventListener throwEvent="signal" signalName="My signal" events="TASK_ASSIGNED" />
  </extensionElements>
</process>
<process id="testEventListeners">
  <extensionElements>
    <activiti:eventListener throwEvent="globalSignal" signalName="My signal" events="TASK_ASSIGNED" />
  </extensionElements>
</process>
<process id="testEventListeners">
  <extensionElements>
    <activiti:eventListener throwEvent="message" messageName="My message" events="TASK_ASSIGNED" />
  </extensionElements>
</process>
<process id="testEventListeners">
  <extensionElements>
    <activiti:eventListener throwEvent="error" errorCode="123" events="TASK_ASSIGNED" />
  </extensionElements>
</process>
  • 如果需要聲明額外的邏輯,是否拋出BPMN事件,可以擴展activiti提供的監聽器類:
    • 在子類中重寫isValidEvent(ActivitiEvent event), 可以防止拋出BPMN事件.對應的類是:
      • org.activiti.engine.impl.bpmn.helper.MessageThrowingEventListener
      • org.activiti.engine.test.api.event.SignalThrowingEventListenerTest
      • org.activiti.engine.impl.bpmn.helper.ErrorThrowingEventListener
流程定義監聽器注意點
  • 事件監聽器只能聲明在process元素中,作為extensionElements的子元素.監聽器不能定義在流程的單個activity下
  • delegateExpression中的表達式無法訪問execution上下文,這與其他表達式不同(比如gateway).它只能引用定義在流程引擎配置的beans屬性中聲明的bean, 或者使用spring(未使用beans屬性)中所有實現了監聽器接口的spring-bean
  • 使用監聽器的class屬性時,只會創建一個實例.監聽器實現不會依賴成員變量,是多線程安全的
  • 當一個非法的事件類型用在events屬性或throwEvent中時,流程定義發布時就會拋出異常(會導致部署失敗)
    • 如果class或delegateExecution由問題:類不存在,不存在的bean引用,或代理類沒有實現監聽器接口
      • 在流程啟動時拋出異常
      • 在第一個有效的流程定義事件被監聽器接收時
    • 所以要保證引用的類正確的放在classpath下,表達式也要引用一個有效的實例

通過API分發事件

  • Activiti我們提供了通過API使用事件機制的方法,允許觸發定義在引擎中的任何自定義事件
  • 建議只觸發類型為CUSTOMActivitiEvents.可以通過RuntimeService觸發事件:
/**
 * Dispatches the given event to any listeners that are registered.
 * @param event event to dispatch.
 *
 * @throws ActivitiException if an exception occurs when dispatching the event or when the {@link ActivitiEventDispatcher}
 * is disabled.
 * @throws ActivitiIllegalArgumentException when the given event is not suitable for dispatching.
 */
 void dispatchEvent(ActivitiEvent event);

支持的事件類型

  • 引擎中每個事件類型都對應org.activiti.engine.delegate.event.ActivitiEventType中的一個枚舉值
事件名稱 事件描述 事件類型
ENGINE_CREATED 監聽器監聽的流程引擎已經創建,准備好接受API調用 ActivitiEvent
ENGINE_CLOSED 監聽器監聽的流程引擎已經關閉,不再接受API調用 ActivitiEvent
ENTITY_CREATED 創建了一個新實體,實體包含在事件中 ActivitiEntityEvent
ENTITY_INITIALIZED 創建了一個新實體,初始化也完成了.如果這個實體的創建會包含子實體的創建,這個事件會在子實體都創建/初始化完成后被觸發,這是與ENTITY_CREATED的區別 ActivitiEntityEvent
ENTITY_UPDATED 更新了已存在的實體,實體包含在事件中 ActivitiEntityEvent
ENTITY_DELETED 刪除了已存在的實體,實體包含在事件中 ActivitiEntityEvent
ENTITY_SUSPENDED 暫停了已存在的實體,實體包含在事件中.會被ProcessDefinitions,ProcessInstances和Tasks拋出 ActivitiEntityEvent
ENTITY_ACTIVATED 激活了已存在的實體,實體包含在事件中.會被ProcessDefinitions,ProcessInstances和Tasks拋出 ActivitiEntityEvent
JOB_EXECUTION_SUCCESS 作業執行成功,job包含在事件中 ActivitiEntityEvent
JOB_EXECUTION_FAILURE 作業執行失敗,作業和異常信息包含在事件中 ActivitiEntityEvent
ActivitiExceptionEvent
JOB_RETRIES_DECREMENTED 因為作業執行失敗,導致重試次數減少.作業包含在事件中 ActivitiEntityEvent
TIMER_FIRED 觸發了定時器,job包含在事件中 ActivitiEntityEvent
JOB_CANCELED 取消了一個作業.事件包含取消的作業.作業可以通過API調用取消,任務完成后對應的邊界定時器也會取消,在新流程定義發布時也會取消 ActivitiEntityEvent
ACTIVITY_STARTED 一個節點開始執行 ActivitiActivityEvent
ACTIVITY_COMPLETED 一個節點成功結束 ActivitiActivityEvent
ACTIVITY_SIGNALED 一個節點收到了一個信號 ActivitiSignalEvent
ACTIVITY_MESSAGE_RECEIVED 一個節點收到了一個消息.在節點收到消息之前觸發,收到后,會觸發ACTIVITY_SIGNALACTIVITY_STARTED, 這會根據節點的類型:邊界事件,事件子流程開始事件 ActivitiMessageEvent
ACTIVITY_ERROR_RECEIVED 一個節點收到了一個錯誤事件.在節點實際處理錯誤之前觸發, 事件的activityId對應着處理錯誤的節點.這個事件后續會是ACTIVITY_SIGNALLEDACTIVITY_COMPLETE, 如果錯誤發送成功的話 ActivitiErrorEvent
UNCAUGHT_BPMN_ERROR 拋出了未捕獲的BPMN錯誤.流程沒有提供針對這個錯誤的處理器.事件的activityId為空 ActivitiErrorEvent
ACTIVITY_COMPENSATE 一個節點將要被補償.事件包含了將要執行補償的節點id ActivitiActivityEvent
VARIABLE_CREATED 創建了一個變量.事件包含變量名,變量值和對應的分支或任務(如果存在) ActivitiVariableEvent
VARIABLE_UPDATED 更新了一個變量.事件包含變量名,變量值和對應的分支或任務(如果存在) ActivitiVariableEvent
VARIABLE_DELETED 刪除了一個變量.事件包含變量名,變量值和對應的分支或任務(如果存在) ActivitiVariableEvent
TASK_ASSIGNED 任務被分配給了一個人員.事件包含任務 ActivitiEntityEvent
TASK_CREATED 創建了新任務.它位於ENTITY_CREATE事件之后.當任務是由流程創建時,這個事件會在TaskListener執行之前被執行 ActivitiEntityEvent
TASK_COMPLETED 任務完成.它會在ENTITY_DELETE事件之前觸發.當任務是流程一部分時,事件會在流程繼續運行之前, 后續事件將是ACTIVITY_COMPLETE,對應着完成任務的節點 ActivitiEntityEvent
TASK_TIMEOUT 任務已超時.在TIMER_FIRED事件之后,會觸發用戶任務的超時事件,當這個任務分配了一個定時器的時候 ActivitiEntityEvent
PROCESS_COMPLETED 流程已結束.在最后一個節點的ACTIVITY_COMPLETED事件之后觸發.當流程到達的狀態,沒有任何后續連線時,流程就會結束 ActivitiEntityEvent
MEMBERSHIP_CREATED 用戶被添加到一個組里.事件包含了用戶和組的id ActivitiMembershipEvent
MEMBERSHIP_DELETED 用戶被從一個組中刪除.事件包含了用戶和組的id ActivitiMembershipEvent
MEMBERSHIPS_DELETED 所有成員被從一個組中刪除.在成員刪除之前觸發這個事件,所以他們都是可以訪問的.因為性能方面的考慮,不會為每個成員觸發單獨的MEMBERSHIP_DELETED事件 ActivitiMembershipEvent
  • 引擎內部所有ENTITY_* 事件都是與實體相關的,實體事件與實體的對應關系:
    • [ENTITY_CREATED],[ENTITY_INITIALIZED],[ENTITY_DELETED]:
      • Attachment
      • Comment
      • Deployment
      • Execution
      • Group
      • IdentityLink
      • Job
      • Model
      • ProcessDefinition
      • ProcessInstance
      • Task
      • User
    • ENTITY_UPDATED:
      • Attachment
      • Deployment
      • Execution
      • Group
      • IdentityLink
      • Job
      • Model
      • ProcessDefinition
      • ProcessInstance
      • Task
      • User
    • ENTITY_SUSPENDED, ENTITY_ACTIVATED:
      • ProcessDefinition
      • ProcessInstance
      • Execution
      • Task

注意

  • 只有同一個流程引擎中的事件會發送給對應的監聽器
  • 如果有很多引擎在同一個數據庫運行,事件只會發送給注冊到對應引擎的監聽器.其他引擎發生的事件不會發送給這個監聽器,無論實際上它們運行在同一個或不同的JVM中
  • 對應的事件類型都包含對應的實體.根據類型或事件,這些實體不能再進行更新(比如,當實例以被刪除).可能的話,使用事件提供的EngineServices來以安全的方式來操作引擎.即使如此,也要小心的對事件對應的實體進行更新,操作
  • 沒有對應歷史的實體事件,因為它們都有運行階段的對應實體


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM