3.配置
创建 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 实例 | 备注 |
---|---|---|
h2 | jdbc:h2:tcp://localhost/activiti | 默认配置的数据库 |
mysql | jdbc:mysql://localhost:3306/activiti?autoReconnect=true | 使用 mysql-connector-java 驱动测试 |
oracle | jdbc:oracle:thin:@localhost:1521:xe | |
postgres | jdbc:postgresql://localhost:5432/activiti | |
db2 | jdbc:db2://localhost:50000/activiti | |
mssql | jdbc: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>
有一个类似的配置叫 knowledgeBaseCacheLimit
和 knowledgeBaseCache
, 它们是配置规则缓存的。只有流程中使用规则任务时才会用到。
日志
从 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
的子类。事件包含(如果有效) 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 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 抛出到外部流程(全局),在流程实例中抛出一个消息事件, 在流程实例中抛出一个错误事件。除了使用 class
或 delegateExpression
, 还使用了 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.MessageThrowingEventListener
和 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 分发事件
我们提供了通过 API 使用事件机制的方法,允许大家触发定义在引擎中的任何自定义事件。 建议(不强制)只触发类型为 CUSTOM
的 ActivitiEvents
。可以通过 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_SIGNAL 或 ACTIVITY_STARTED ,这会根据节点的类型(边界事件,事件子流程开始事件) | org.activiti...ActivitiMessageEvent |
ACTIVITY_ERROR_RECEIVED | 一个节点收到了一个错误事件。在节点实际处理错误之前触发。 事件的 activityId 对应着处理错误的节点。 这个事件后续会是 ACTIVITY_SIGNALLED 或 ACTIVITY_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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论