工作流引擎详解!工作流开源框架ACtiviti的详细配置以及安装和使用-LMLPHP

创建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,mysql,oracle,postgres,mssql,db2}
      • 如果没使用默认的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中的一个枚举值
  • 引擎内部所有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来以安全的方式来操作引擎.即使如此,也要小心的对事件对应的实体进行更新,操作
  • 没有对应历史的实体事件,因为它们都有运行阶段的对应实体
05-27 21:32