3.配置

优质
小牛编辑
117浏览
2023-12-01

创建ProcessEngine

Activiti流程引擎的配置文件是名为activiti.cfg.xml的XML文件。 注意这与使用Spring方式创建流程引擎 是一样的。

获得ProcessEngine最简单的办法是 使用org.activiti.engine.ProcessEngines类:

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>

注意配置XML文件其实是一个spring的配置文件。 但不是说Activiti只能用在Spring环境中! 我们只是利用了Spring的解析和依赖注入功能 来构建引擎。

配置文件中使用的ProcessEngineConfiguration可以通过编程方式创建。 可以配置不同的bean id(比如,第三行)。

ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String resource);
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String resource, String beanName);
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(InputStream inputStream);
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName);

也可以不使用配置文件,基于默认创建配置 (参考各种支持类)

ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();

所有这些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环境下使用流程引擎。 参考Spring集成章节。

  • org.activiti.engine.impl.cfg.JtaProcessEngineConfiguration: 单独运行流程引擎,并使用JTA事务。

数据库配置

Activiti可能使用两种方式配置数据库。 第一种方式是定义数据库配置参数:

  • jdbcUrl: 数据库的JDBC URL。

  • jdbcDriver: 对应不同数据库类型的驱动。

  • jdbcUsername: 连接数据库的用户名。

  • jdbcPassword: 连接数据库的密码。

基于JDBC参数配置的数据库连接 会使用默认的MyBatis连接池。 下面的参数可以用来配置连接池(来自MyBatis参数):

  • jdbcMaxActiveConnections: 连接池中处于被使用状态的连接的最大值。默认为10。

  • jdbcMaxIdleConnections: 连接池中处于空闲状态的连接的最大值。

  • jdbcMaxCheckoutTime: 连接被取出使用的最长时间,超过时间会被强制回收。 默认为20000(20秒)。

  • jdbcMaxWaitTime: 这是一个底层配置,让连接池可以在长时间无法获得连接时, 打印一条日志,并重新尝试获取一个连接。(避免因为错误配置导致沉默的操作失败)。 默认为20000(20秒)。

示例数据库配置:

<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="" />
     

也可以使用javax.sql.DataSource。 (比如,Apache Commons的DBCP):

<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" />
    ...
     

注意,Activiti的发布包中没有这些类。 你要自己把对应的类(比如,从DBCP里)放到你的classpath下。

无论你使用JDBC还是DataSource的方式,都可以设置下面的配置:

  • databaseType: 一般不用设置,因为可以自动通过数据库连接的元数据获取。 只有自动检测失败时才需要设置。 可能的值有:{h2, mysql, oracle, postgres, mssql, db2}。 如果没使用默认的H2数据库就必须设置这项。 这个配置会决定使用哪些创建/删除脚本和查询语句。 参考支持数据库章节 了解支持哪些类型。

  • databaseSchemaUpdate: 设置流程引擎启动和关闭时如何处理数据库表。

    • false(默认):检查数据库表的版本和依赖库的版本, 如果版本不匹配就抛出异常。

    • true: 构建流程引擎时,执行检查,如果需要就执行更新。 如果表不存在,就创建。

    • create-drop: 构建流程引擎时创建数据库表, 关闭流程引擎时删除这些表。

支持的数据库

下面列出Activiti使用的数据库类型(大小写敏感)。

Table 3.1.支持的数据库

Activiti数据库类型JDBC URL实例备注
h2jdbc:h2:tcp://localhost/activiti默认配置的数据库
mysqljdbc:mysql://localhost:3306/activiti?autoReconnect=true使用mysql-connector-java驱动测试
oraclejdbc:oracle:thin:@localhost:1521:xe 
postgresjdbc:postgresql://localhost:5432/activiti 
db2jdbc:db2://localhost:50000/activiti 
mssqljdbc:sqlserver://localhost:1433/activiti 

创建数据库表

下面是创建数据库表最简单的办法:

  • 把activiti-engine的jar放到classpath下

  • 添加对应的数据库驱动

  • 把Activiti配置文件 (activiti.cfg.xml) 放到 classpath下, 指向你的数据库(参考数据库配置章节)

  • 执行 DbSchemaCreate 类的main方法

然而,只有数据库管理员可以执行DDL语句。 在生产环境,也也是最明智的选择。 SQL DDL语句可以从Activiti下载页或Activiti发布目录里找到,在database子目录下。 脚本也包含在引擎的jar中(activiti-engine-x.jar), 在org/activiti/db/create包下(drop目录里是删除语句)。 SQL文件的命名方式如下

activiti.{db}.{create|drop}.{type}.sql

其中 db 是 支持的数据库, type

  • engine: 引擎执行的表。必须。

  • identity: 包含用户,群组,用户与组之间的关系的表。 这些表是可选的,只有使用引擎自带的默认身份管理时才需要。

  • history: 包含历史和审计信息的表。可选的:历史级别设为none时不会使用。 注意这也会引用一些需要把数据保存到历史表中的功能(比如任务的评论)。

MySQL用户需要注意: 版本低于5.6.4的MySQL不支持毫秒精度的timstamp或date类型。 更眼中的是,有些版本会在尝试创建这样一列时抛出异常,而有些版本则不会。 在执行自动创建/更新时,引擎会在执行过程中修改DDL。 当使用DDL时,可以选择通用版本和名为mysql55的文件。 (它适合所有版本低于5.6.4的情况)。 后一个文件会将列的类型设置为没有毫秒的情况。

总结一下,对于MySQL版本会执行如下操作

  • <5.6: 不支持毫秒精度。可以使用DDL文件(包含mysql55的文件)。可以实现自动创建/更新。

  • 5.6.0 - 5.6.3: 不支持毫秒精度。无法自动创建/更新。建议更新到新的数据库版本。如果真的需要的话,也可以使用mysql 5.5

  • 5.6.4+:支持毫秒精度。可以使用DDL文件(默认包含mysql的文件)。可以实现自动创建、更新。

注意对于已经更新了MySQL数据库,而且Activiti表已经创建/更新的情况, 必须手工修改列的类型。

理解数据库表的命名

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允许查询(ManagementService.createJobQuery)和执行job (ManagementService.executeJob),所以job可以在单元测试中控制。 要避免与job执行器冲突,可以关闭它。

默认,JobExecutor在流程引擎启动时就会激活。 如果不想在流程引擎启动后自动激活JobExecutor,可以设置

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

配置邮件服务器

可以选择配置邮件服务器。Activiti支持在业务流程中发送邮件。 想真正的发送一个email,必须配置一个真实的SMTP邮件服务器。 参考e-mail任务。

配置历史

可以选择定制历史存储的配置。你可以通过配置影响引擎的历史功能。 参考历史配置。

<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开始,SLF4J被用作日志框架,替换了之前使用java.util.logging。 所有日志(activiti, spring, mybatis等等)都转发给SLF4J 允许使用你选择的日志实现。

默认activiti-engine依赖中没有提供SLF4J绑定的jar, 需要根据你的实际需要使用日志框架。如果没有添加任何实现jar,SLF4J会使用NOP-logger,不使用任何日志,不会发出警告,而且什么日志都不会记录。 可以通过http://www.slf4j.org/codes.html#StaticLoggerBinder了解这些实现。

使用Maven,比如使用一个依赖(这里使用log4j),注意你还需要添加一个version:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
</dependency>

activiti-explorer和activiti-rest应用都使用了Log4j绑定。执行所有activiti-*模块的单元测试页使用了Log4j。

特别提醒如果容器classpath中存在commons-logging: 为了把spring日志转发给SLF4J,需要使用桥接(参考http://www.slf4j.org/legacy.html#jclOverSLF4J)。 如果你的容器提供了commons-logging实现,请参考下面网页:http://www.slf4j.org/codes.html#release来确保稳定性。

使用Maven的实例(忽略版本):

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jcl-over-slf4j</artifactId>
</dependency>

映射诊断上下文

在5.13中,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 5.15中实现了一种事件机制。它允许在引擎触发事件时获得提醒。 参考所有支持的事件类型了解有效的事件。

可以为对应的事件类型注册监听器,在这个类型的任何时间触发时都会收到提醒。 你可以添加引擎范围的事件监听器通过配置, 添加引擎范围的事件监听器在运行阶段使用API, 或添加event-listener到特定流程定义的BPMN XML中。

所有分发的事件,都是org.activiti.engine.delegate.event.ActivitiEvent的子类。事件包含(如果有效)typeexecutionIdprocessInstanceIdprocessDefinitionId。 对应的事件会包含事件发生时对应上下文的额外信息, 这些额外的载荷可以在支持的所有事件类型中找到。

事件监听器实现

实现事件监听器的唯一要求是实现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/error的BPMN事件。

让监听器执行用户定义的逻辑

下面代码为一个流程定义添加了两个监听器。第一个监听器会接收所有类型的事件,它是通过全类名定义的。 第二个监听器只接收作业成功或失败的事件,它使用了定义在流程引擎配置中的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.test.api.event.SignalThrowingEventListenerTest, org.activiti.engine.impl.bpmn.helper.MessageThrowingEventListenerorg.activiti.engine.impl.bpmn.helper.ErrorThrowingEventListener.

流程定义中监听器的注意事项

  • 事件监听器只能声明在process元素中,作为extensionElements的子元素。 监听器不能定义在流程的单个activity下。

  • delegateExpression中的表达式无法访问execution上下文,这与其他表达式不同(比如gateway)。 它只能引用定义在流程引擎配置的beans属性中声明的bean,或者使用spring(未使用beans属性)中所有实现了监听器接口的spring-bean。

  • 在使用监听器的 class 属性时,只会创建一个实例。记住监听器实现不会依赖成员变量, 确认是多线程安全的。

  • 当一个非法的事件类型用在events属性或throwEvent中时,流程定义发布时就会抛出异常。(会导致部署失败)。如果classdelegateExecution由问题(类不存在,不存在的bean引用,或代理类没有实现监听器接口),会在流程启动时抛出异常(或在第一个有效的流程定义事件被监听器接收时)。所以要保证引用的类正确的放在classpath下,表达式也要引用一个有效的实例。

通过API分发事件

我们提供了通过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中的一个枚举值。

Table 3.2.支持的事件

事件名称描述事件类型
ENGINE_CREATED监听器监听的流程引擎已经创建完毕,并准备好接受API调用。org.activiti...ActivitiEvent
ENGINE_CLOSED监听器监听的流程引擎已经关闭,不再接受API调用。org.activiti...ActivitiEvent
ENTITY_CREATED创建了一个新实体。实体包含在事件中。org.activiti...ActivitiEntityEvent
ENTITY_INITIALIZED创建了一个新实体,初始化也完成了。如果这个实体的创建会包含子实体的创建,这个事件会在子实体都创建/初始化完成后被触发,这是与ENTITY_CREATED的区别。org.activiti...ActivitiEntityEvent
ENTITY_UPDATED更新了已存在的实体。实体包含在事件中。org.activiti...ActivitiEntityEvent
ENTITY_DELETED删除了已存在的实体。实体包含在事件中。org.activiti...ActivitiEntityEvent
ENTITY_SUSPENDED暂停了已存在的实体。实体包含在事件中。会被ProcessDefinitions, ProcessInstances 和 Tasks抛出。org.activiti...ActivitiEntityEvent
ENTITY_ACTIVATED激活了已存在的实体,实体包含在事件中。会被ProcessDefinitions, ProcessInstances 和 Tasks抛出。org.activiti...ActivitiEntityEvent
JOB_EXECUTION_SUCCESS作业执行成功。job包含在事件中。org.activiti...ActivitiEntityEvent
JOB_EXECUTION_FAILURE作业执行失败。作业和异常信息包含在事件中。org.activiti...ActivitiEntityEvent and org.activiti...ActivitiExceptionEvent
JOB_RETRIES_DECREMENTED因为作业执行失败,导致重试次数减少。作业包含在事件中。org.activiti...ActivitiEntityEvent
TIMER_FIRED触发了定时器。job包含在事件中。org.activiti...ActivitiEntityEvent
ACTIVITY_STARTED一个节点开始执行org.activiti...ActivitiActivityEvent
ACTIVITY_COMPLETED一个节点成功结束org.activiti...ActivitiActivityEvent
ACTIVITY_SIGNALED一个节点收到了一个信号org.activiti...ActivitiSignalEvent
ACTIVITY_MESSAGE_RECEIVED一个节点收到了一个消息。在节点收到消息之前触发。收到后,会触发ACTIVITY_SIGNALACTIVITY_STARTED,这会根据节点的类型(边界事件,事件子流程开始事件)org.activiti...ActivitiMessageEvent
ACTIVITY_ERROR_RECEIVED一个节点收到了一个错误事件。在节点实际处理错误之前触发。 事件的activityId对应着处理错误的节点。 这个事件后续会是ACTIVITY_SIGNALLEDACTIVITY_COMPLETE, 如果错误发送成功的话。org.activiti...ActivitiErrorEvent
UNCAUGHT_BPMN_ERROR抛出了未捕获的BPMN错误。流程没有提供针对这个错误的处理器。 事件的activityId为空。org.activiti...ActivitiErrorEvent
ACTIVITY_COMPENSATE一个节点将要被补偿。事件包含了将要执行补偿的节点id。org.activiti...ActivitiActivityEvent
VARIABLE_CREATED创建了一个变量。事件包含变量名,变量值和对应的分支或任务(如果存在)。org.activiti...ActivitiVariableEvent
VARIABLE_UPDATED更新了一个变量。事件包含变量名,变量值和对应的分支或任务(如果存在)。org.activiti...ActivitiVariableEvent
VARIABLE_DELETED删除了一个变量。事件包含变量名,变量值和对应的分支或任务(如果存在)。org.activiti...ActivitiVariableEvent
TASK_ASSIGNED任务被分配给了一个人员。事件包含任务。org.activiti...ActivitiEntityEvent
TASK_COMPLETED任务被完成了。它会在ENTITY_DELETE事件之前触发。当任务是流程一部分时,事件会在流程继续运行之前, 后续事件将是ACTIVITY_COMPLETE,对应着完成任务的节点。org.activiti...ActivitiEntityEvent
MEMBERSHIP_CREATED用户被添加到一个组里。事件包含了用户和组的id。org.activiti...ActivitiMembershipEvent
MEMBERSHIP_DELETED用户被从一个组中删除。事件包含了用户和组的id。org.activiti...ActivitiMembershipEvent
MEMBERSHIPS_DELETED所有成员被从一个组中删除。在成员删除之前触发这个事件,所以他们都是可以访问的。 因为性能方面的考虑,不会为每个成员触发单独的MEMBERSHIP_DELETED事件。org.activiti...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来以安全的方式来操作引擎。即使如此,你需要小心的对事件对应的实体进行更新/操作。

没有对应历史的实体事件,因为它们都有运行阶段的对应实体。