返回介绍

3.配置

发布于 2019-10-28 05:33:27 字数 27566 浏览 1066 评论 0 收藏 0

创建 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 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 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 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 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 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 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 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>
<extensionElements>
<activiti:eventListener class="org.activiti.engine.test.MyEventListener" />
<activiti:eventListener delegateExpression="${testEventListener}" events="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" />
</extensionElements>

...

</process>

对于实体相关的事件,也可以设置为针对某个流程定义的监听器,实现只监听发生在某个流程定义上的某个类型实体事件。 下面的代码演示了如何实现这种功能。可以用于所有实体事件(第一个例子),也可以只监听特定类型的事件(第二个例子)。

<process>
<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>
<extensionElements>
<activiti:eventListener throwEvent="signal" signalName="My signal" events="TASK_ASSIGNED" />
</extensionElements>
</process>
<process>
<extensionElements>
<activiti:eventListener throwEvent="globalSignal" signalName="My signal" events="TASK_ASSIGNED" />
</extensionElements>
</process>
<process>
<extensionElements>
<activiti:eventListener throwEvent="message" messageName="My message" events="TASK_ASSIGNED" />
</extensionElements>
</process>
<process>
<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 来以安全的方式来操作引擎。即使如此,你需要小心的对事件对应的实体进行更新/操作。

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文