跳到主要内容

配置

Doubao 中英对照 Configuration

创建流程引擎​

Flowable 流程引擎通过一个名为 flowable.cfg.xml 的 XML 文件配置。请注意,如果你使用的是构建流程引擎的 Spring 方式,则不适用此方式。

获取 ProcessEngine 最简单的方式是使用 org.flowable.engine.ProcessEngines 类:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine()

这会在 classpath 上查找 flowable.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.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration">

<property name="jdbcUrl" value="jdbc:h2:mem:flowable;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="asyncExecutorActivate" value="false" />

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

</beans>

请注意,这个配置 XML 实际上是一个 Spring 配置。**这并不意味着 Flowable 只能在 Spring 环境中使用!**我们只是在内部利用 Spring 的解析和依赖注入能力来构建引擎。

也可以通过配置文件以编程方式创建 ProcessEngineConfiguration 对象。还可以使用不同的 bean id(例如参见第 3 行)。

ProcessEngineConfiguration.
createProcessEngineConfigurationFromResourceDefault();
createProcessEngineConfigurationFromResource(String resource);
createProcessEngineConfigurationFromResource(String resource, String beanName);
createProcessEngineConfigurationFromInputStream(InputStream inputStream);
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")
.setAsyncExecutorActivate(false)
.buildProcessEngine();

ProcessEngineConfiguration Bean​

flowable.cfg.xml 必须包含一个 id 为 'processEngineConfiguration' 的 bean。

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

这个 bean 随后用于构建 ProcessEngine。可以使用多个类来定义 processEngineConfiguration。这些类代表不同的环境,并相应地设置默认值。最佳实践是选择最匹配你环境的类,以最小化配置引擎所需的属性数量。目前可用的类有:

  • org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration:流程引擎以独立方式使用。Flowable 会负责所有事务。默认情况下,数据库仅在引擎启动时检查(如果不存在 Flowable schema 或 schema 版本不正确,则抛出异常)。
  • org.flowable.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration:这是一个用于单元测试的便利类。Flowable 会负责所有事务。默认使用 H2 内存数据库。数据库会在引擎启动和关闭时创建和删除。使用此类时,可能不需要额外配置(除非使用作业执行器或邮件功能等)。
  • org.flowable.spring.SpringProcessEngineConfiguration:在 Spring 环境中使用流程引擎时使用。更多信息参见 Spring 集成小节。
  • org.flowable.engine.impl.cfg.JtaProcessEngineConfiguration:引擎以独立模式运行、使用 JTA 事务时使用。

数据库配置​

配置 Flowable 引擎所使用的数据库有两种方式。第一种是定义数据库的 JDBC 属性:

  • 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:flowable;DB_CLOSE_DELAY=1000" />
<property name="jdbcDriver" value="org.h2.Driver" />
<property name="jdbcUsername" value="sa" />
<property name="jdbcPassword" value="" />

我们的基准测试表明,MyBatis 连接池在处理大量并发请求时并不是最高效或最有韧性的。因此,建议使用一个 javax.sql.DataSource 实现并将其注入流程引擎配置(例如 HikariCP、Tomcat JDBC Connection Pool 等):

<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/flowable" />
<property name="username" value="flowable" />
<property name="password" value="flowable" />
<property name="defaultAutoCommit" value="false" />
</bean>

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

<property name="dataSource" ref="dataSource" />
...

请注意,Flowable 并不附带定义此类数据源的库。因此你需要确保这些库位于你的 classpath 上。

无论你使用 JDBC 方式还是数据源方式,都可以设置以下属性:

  • databaseType:通常不需要指定此属性,因为它会从数据库连接元数据中自动检测。仅在自动检测失败时才应指定。可能的取值:{h2, mysql, oracle, postgres, mssql, db2}。此设置将决定使用哪些建表/删表脚本和查询。受支持类型的概览参见受支持的数据库小节。
  • databaseSchemaUpdate:设置流程引擎启动和关闭时处理数据库 schema 的策略。
    • false(默认):创建流程引擎时检查数据库 schema 版本与库是否一致,版本不匹配则抛出异常。
    • true:构建流程引擎时进行检查,并在必要时更新 schema。如果 schema 不存在则创建。
    • create-drop:创建流程引擎时创建 schema,关闭流程引擎时删除 schema。

JNDI 数据源配置​

默认情况下,Flowable 的数据库配置包含在每个 Web 应用 WEB-INF/classes 下的 db.properties 文件中。这并不总是理想的,因为这要求用户要么修改 Flowable 源码中的 db.properties 并重新编译 WAR 文件,要么解包 WAR 并在每次部署时修改 db.properties。

通过使用 JNDI(Java Naming and Directory Interface)获取数据库连接,该连接完全由 Servlet 容器管理,配置可以在 WAR 部署之外管理。这也允许比 db.properties 文件所提供的更精细地控制连接参数。

配置​

JNDI 数据源的配置因你所使用的 servlet 容器而异。以下说明适用于 Tomcat,但对于其他容器应用,请参阅你的容器应用文档。

如果使用 Tomcat,JNDI 资源在 $CATALINA_BASE/conf/[enginename]/[hostname]/[warname].xml 中配置(对于 Flowable UI,通常是 $CATALINA_BASE/conf/Catalina/localhost/flowable-app.xml)。默认 context 在应用首次部署时从 Flowable WAR 文件复制,所以如果它已存在,你需要替换它。例如要把 JNDI 资源改为应用连接 MySQL 而非 H2,把文件改为如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/flowable-app">
<Resource auth="Container"
name="jdbc/flowableDB"
type="javax.sql.DataSource"
description="JDBC DataSource"
url="jdbc:mysql://localhost:3306/flowable"
driverClassName="com.mysql.jdbc.Driver"
username="sa"
password=""
defaultAutoCommit="false"
initialSize="5"
maxWait="5000"
maxActive="120"
maxIdle="5"/>
</Context>

JNDI 属性​

要配置 JNDI 数据源,请在 Flowable UI 的 properties 文件中使用以下属性:

  • spring.datasource.jndi-name=:数据源的 JNDI 名称。
  • datasource.jndi.resourceRef:设置是否在 J2EE 容器中进行查找;例如,如果 JNDI 名称尚未包含前缀 "java:comp/env/",则需要添加。默认值为 "true"。

自定义属性​

系统属性也可以在 flowable.cfg.xml 中以 $\{propertyName:defaultValue} 的格式使用。

<property name="jdbcUrl" value="${jdbc.url:jdbc:h2:mem:flowable;DB_CLOSE_DELAY=1000}" />
<property name="jdbcDriver" value="${jdbc.driver:org.h2.Driver}" />
<property name="jdbcUsername" value="${jdbc.username:sa}" />
<property name="jdbcPassword" value="${jdbc.password:}" />

使用此配置时,如果属性 jdbc.url 可用,则将用于 ProcessEngineConfiguration 的 jdbcUrl。否则使用第一个 : 之后的值。

也可以通过使用一个 org.springframework.beans.factory.config.PropertyPlaceholderConfigurer 类型的 bean 来定义从系统中读取属性的位置。

带自定义属性位置的配置示例

<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.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:/opt/conf/flowable.properties" />
</bean>

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

<property name="jdbcUrl" value="${jdbc.url:jdbc:h2:mem:flowable;DB_CLOSE_DELAY=1000}" />
<property name="jdbcDriver" value="${jdbc.driver:org.h2.Driver}" />
<property name="jdbcUsername" value="${jdbc.username:sa}" />
<property name="jdbcPassword" value="${jdbc.password:}" />

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

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

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

</beans>

使用此配置时,属性将首先在 /opt/conf/flowable.properties 文件中查找。

受支持的数据库​

下面列出 Flowable 用于指代数据库的类型(区分大小写!)。

Flowable 数据库类型示例 JDBC URL备注
h2jdbc:h2:tcp://localhost/flowable默认配置的数据库
mysqljdbc:mysql://localhost:3306/flowable?autoReconnect=true使用 mysql-connector-java 数据库驱动测试
oraclejdbc:oracle:thin:@localhost:1521:xe
postgresjdbc:postgresql://localhost:5432/flowable
db2jdbc:db2://localhost:50000/flowable
mssqljdbc:sqlserver://localhost:1433;databaseName=flowable (jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver) 或 jdbc:jtds:sqlserver://localhost:1433/flowable (jdbc.driver=net.sourceforge.jtds.jdbc.Driver)使用 Microsoft JDBC Driver 4.0 (sqljdbc4.jar) 和 JTDS Driver 测试

创建数据库表​

为你的数据库创建数据库表最简单的方式是:

  • 将 flowable-engine JAR 加入你的 classpath
  • 添加合适的数据库驱动
  • 将指向你数据库的 Flowable 配置文件(flowable.cfg.xml)加入 classpath(参见数据库配置小节)
  • 执行 DbSchemaCreate 类的 main 方法

然而,通常只有数据库管理员才能在数据库上执行 DDL 语句。在生产系统上,这也是最明智的选择。SQL DDL 语句可以在 Flowable 下载页面或 Flowable 发行目录的 database 子目录中找到。这些脚本也在引擎 JAR(flowable-engine-x.jar)的 org/flowable/db/create 包中(drop 文件夹包含删表语句)。SQL 文件的形式为

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

其中 db 是任一受支持的数据库,type 为:

  • **engine:**引擎执行所需的表。必需。
  • **history:**包含历史和审计信息的表。可选:当历史级别设为 none 时不需要。请注意,这也会禁用一些将数据存储在历史库中的功能(例如对任务的评论)。

**MySQL 用户注意:**低于 5.6.4 的 MySQL 版本不支持毫秒精度的时间戳或日期。更糟糕的是,某些版本在尝试创建此类列时会抛出异常,而其他版本则不会。在自动创建/升级时,引擎会在执行 DDL 时修改它。使用 DDL 文件方式时,常规版本和一个含 mysql55 的特殊文件都可用(适用于低于 5.6.4 的任何版本)。后一种文件中的列类型没有毫秒精度。

具体来说,以下规则适用于各 MySQL 版本:

  • **<5.6:**不支持毫秒精度。有对应 DDL 文件(查找含 mysql55 的文件)。自动创建/升级开箱即用。
  • **5.6.0 - 5.6.3:**不支持毫秒精度。自动创建/升级无法工作。无论如何都建议升级到更新的数据库版本。如果确实需要,可以使用 mysql 5.5 的 DDL 文件。
  • **5.6.4+:**支持毫秒精度。有对应 DDL 文件(默认含 mysql 的文件)。自动创建/升级开箱即用。

请注意,如果之后升级 MySQL 数据库、而 Flowable 表已经创建/升级,列类型的变更将必须手动完成!

数据库表名说明​

Flowable 的数据库名全部以 ACT_ 开头。第二部分是两个字符,标识该表的用例。该用例也大致对应服务 API。

  • ACT_RE_*:'RE' 代表 repository(仓库)。带此前缀的表包含'静态'信息,如流程定义和流程资源(图片、规则等)。
  • ACT_RU_*:'RU' 代表 runtime(运行时)。这些是运行时表,包含流程实例、用户任务、变量、作业等的运行时数据。Flowable 仅在流程实例执行期间存储运行时数据,并在流程实例结束时移除记录。这使得运行时表保持小而快。
  • ACT_HI_*:'HI' 代表 history(历史)。这些表包含历史数据,如过去的流程实例、变量、任务等。
  • ACT_GE_*:通用数据,用于各种用例。

数据库升级​

在运行升级之前,请务必备份你的数据库(使用你的数据库备份能力)。

默认情况下,每次创建流程引擎时都会进行版本检查。这通常发生在你的应用或 Flowable webapp 启动时。如果 Flowable 库发现库版本与 Flowable 数据库表版本不一致,则抛出异常。

要升级,首先要在你的 flowable.cfg.xml 配置文件中放入以下配置属性:

<beans >

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

</beans>

**另外,请将适合你的数据库的驱动加入 classpath。**升级你的应用中的 Flowable 库。或者启动一个新版本的 Flowable,并把它指向包含旧版本数据的数据库。当 databaseSchemaUpdate 设为 true 时,Flowable 会在第一次发现库与数据库 schema 不同步时,自动把数据库 schema 升级到最新版本。

**作为替代,你也可以运行升级 DDL 语句。**也可以运行 Flowable 下载页面上提供的升级数据库脚本。

Job Executor(自 6.0.0 版本起)​

Flowable v5 的异步执行器是 Flowable V6 中唯一可用的作业执行器,因为它是在 Flowable 引擎中执行异步作业的更高性能、对数据库更友好的方式。Flowable 5 的旧作业执行器在 V6 中不再可用。更多信息参见用户指南的高级小节。

此外,如果在 Java EE 7 下运行,可以使用符合 JSR-236 的 ManagedAsyncJobExecutor,让容器管理线程。要启用它们,应按如下方式在配置中传入线程工厂:

<bean id="threadFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/ee/concurrency/factory/default" />
</bean>

<bean id="customJobExecutor" class="org.flowable.engine.impl.jobexecutor.ManagedAsyncJobExecutor">
<!-- ... -->
<property name="threadFactory" ref="threadFactory" />
<!-- ... -->
</bean>

如果未指定线程工厂,托管实现会回退到其默认的对应实现。

启用 Job Executor​

AsyncExecutor 是一个管理线程池、用于触发定时器和其他异步任务的组件。

默认情况下,AsyncExecutor 不会激活和启动。使用以下配置可以让异步执行器随 Flowable 引擎一起启动。

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

asyncExecutorActivate 属性指示 Flowable 引擎在启动时启动异步执行器。

邮件服务器配置​

配置邮件服务器是可选的。Flowable 支持在业务流程中发送电子邮件。要实际发送电子邮件,需要有效的 SMTP 邮件服务器配置。配置选项参见电子邮件任务。

历史配置​

自定义历史存储配置是可选的。这允许你调整影响引擎历史能力的设置。更多信息参见历史配置。

<property name="history" value="audit" />

在表达式和脚本中暴露配置 Bean​

默认情况下,你在 flowable.cfg.xml 配置或你自己的 Spring 配置文件中指定的所有 bean 都可用于表达式和脚本。如果你想限制配置文件中 bean 的可见性,可以在流程引擎配置中配置一个名为 beans 的属性。ProcessEngineConfiguration 中的 beans 属性是一个 map。当你指定该属性时,只有该 map 中指定的 bean 对表达式和脚本可见。暴露的 bean 将以你在 map 中指定的名称暴露。

部署缓存配置​

所有流程定义(在解析之后)都会被缓存,以避免每次需要流程定义时都访问数据库,也因为流程定义数据不会变化。默认情况下,此缓存没有限制。要限制流程定义缓存,添加以下属性:

<property name="processDefinitionCacheLimit" value="10" />

设置此属性会把默认的 hashmap 缓存替换为一个带有限制的 LRU 缓存。当然,此属性的'最佳'值取决于存储的流程定义总数以及所有运行中流程实例实际使用的流程定义数量。

你也可以注入自己的缓存实现。它必须是一个实现 org.flowable.engine.impl.persistence.deploy.DeploymentCache 接口的 bean:

<property name="processDefinitionCache">
<bean class="org.flowable.MyCache" />
</property>

有一个类似的属性名为 knowledgeBaseCacheLimit 和 knowledgeBaseCache,用于配置规则缓存。仅当你在流程中使用规则任务时才需要。

日志​

所有日志(flowable、spring、mybatis 等)都通过 SLF4J 路由,并允许选择你所喜欢的日志实现。

**默认情况下,flowable-engine 依赖中不包含任何 SLF4J 绑定 JAR,你应在项目中添加它以使用你所选的日志框架。**如果没有添加实现 JAR,SLF4J 将使用一个 NOP 日志器,除了一条'将不记录任何日志'的警告外什么都不记录。更多信息参见这些绑定说明 http://www.slf4j.org/codes.html#StaticLoggerBinder。

使用 Maven 时,例如添加这样一个依赖(这里使用 log4j),注意你仍需要添加版本:

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

flowable-rest webapp 配置为使用 Log4j 绑定。运行所有 flowable-* 模块的测试时也使用 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>

映射诊断上下文(Mapped Diagnostic Contexts)​

Flowable 支持 SLF4J 的映射诊断上下文(Mapped Diagnostic Contexts)特性。这些基本信息会连同将要记录的内容一起传给底层日志器:

  • 流程定义 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

当日志包含需要实时检查的信息时(例如通过日志分析器),这很有用。

事件处理器​

Flowable 引擎中的事件机制允许你在引擎内发生各种事件时得到通知。可用事件的概览参见所有受支持的事件类型。

可以为某些类型的事件注册监听器,而不是在派发任何类型事件时都得到通知。你既可以通过配置添加引擎范围的事件监听器,也可以在运行时使用 API添加引擎范围的事件监听器,或向 BPMN XML 中的特定流程定义添加事件监听器。

所有派发的事件都是 org.flowable.engine.common.api.delegate.event.FlowableEvent 的子类型。事件会暴露(如可用)类型、executionId、processInstanceId 和 processDefinitionId。某些事件包含与所发生事件相关的额外上下文;关于额外负载的更多信息可在所有受支持的事件类型列表中找到。

事件监听器实现​

事件监听器的唯一要求是实现 org.flowable.common.engine.api.delegate.event.FlowableEventListener。下面是一个监听器实现示例,它把收到的所有事件输出到标准输出,但与作业执行相关的事件除外:

public class MyEventListener implements FlowableEventListener {

@Override
public void onEvent(FlowableEvent event) {

if(event.getType() == FlowableEngineEventType.JOB_EXECUTION_SUCCESS) {
System.out.println("A job well done!");
} else if (event.getType() == FlowableEngineEventType.JOB_EXECUTION_FAILURE) {
System.out.println("A job has failed...");
} else {
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;
}

@Override
public boolean isFireOnTransactionLifecycleEvent() {
return false;
}

@Override
public String getOnTransaction() {
return null;
}
}

isFailOnException() 方法决定:当事件派发时 onEvent(..) 方法抛出异常会发生什么。返回 false 时,异常被忽略。返回 true 时,异常不会被忽略并向上冒泡,实际上使当前正在执行的命令失败。如果事件是 API 调用(或任何其他事务性操作,例如作业执行)的一部分,事务将回滚。如果事件监听器中的行为不是业务关键的,建议返回 false。

isFireOnTransactionLifecycleEvent() 方法决定:此事件监听器是在事件发生时立即触发,还是在由 getOnTransaction() 方法确定的事务生命周期事件上触发。事务生命周期事件的受支持取值为:COMMITTED、ROLLED_BACK、COMMITTING、ROLLINGBACK。

Flowable 提供了一些基础实现,以便利事件监听器的常见用例。它们可以用作基类或监听器实现示例:

  • org.flowable.engine.delegate.event.BaseEntityEventListener:一个事件监听器基类,可用于监听特定类型实体或所有实体的实体相关事件。它隐藏了类型检查,并提供 4 个应被覆写的方法:当实体被创建、更新或删除时的 onCreate(..)、onUpdate(..) 和 onDelete(..)。对于所有其他实体相关事件,会调用 onEntityEvent(..)。

配置与设置​

如果在流程引擎配置中配置了事件监听器,它会在流程引擎启动时激活,并在引擎后续重启后保持激活。

eventListeners 属性期望一个 org.flowable.common.engine.api.delegate.event.FlowableEventListener 实例列表。与通常一样,你既可以声明内联 bean 定义,也可以使用对已有 bean 的引用。下面的片段向配置添加了一个事件监听器,当任何事件被派发(无论其类型)时都会得到通知:

<bean id="processEngineConfiguration"
class="org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration">
...
<property name="eventListeners">
<list>
<bean class="org.flowable.engine.example.MyEventListener" />
</list>
</property>
</bean>

要在某些类型的事件被派发时得到通知,使用 typedEventListeners 属性,它期望一个 map。map 条目的键是逗号分隔的事件名列表(或单个事件名)。map 条目的值是 org.flowable.common.engine.api.delegate.event.FlowableEventListener 实例列表。下面的片段向配置添加了一个事件监听器,当作业执行成功或失败时得到通知:

<bean id="processEngineConfiguration"
class="org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration">
...
<property name="typedEventListeners">
<map>
<entry key="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" >
<list>
<bean class="org.flowable.engine.example.MyJobEventListener" />
</list>
</entry>
</map>
</property>
</bean>

派发事件的顺序由监听器添加的顺序决定。首先按列表中定义的顺序调用所有普通事件监听器(eventListeners 属性)。之后,如果派发了正确类型的事件,再调用所有类型化事件监听器(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(FlowableEventListener 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(FlowableEventListener listenerToAdd, FlowableEventType... 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(FlowableEventListener listenerToRemove);

请注意,在运行时添加的监听器在引擎重启后不会保留。

向流程定义添加监听器​

可以向特定流程定义添加监听器。这些监听器只会被调用于与该流程定义相关的事件,以及与使用该特定流程定义启动的流程实例相关的所有事件。监听器实现可以使用全限定类名定义、使用一个解析为实现监听器接口的 bean 的表达式,或配置为抛出 message/signal/error BPMN 事件。

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

下面的片段向一个流程定义添加了 2 个监听器。第一个监听器接收任意类型的事件,使用基于全限定类名的监听器实现。第二个监听器仅在作业成功执行或失败时得到通知,使用在流程引擎配置的 beans 属性中定义的监听器。

<process id="testEventListeners">
<extensionElements>
<flowable:eventListener class="org.flowable.engine.test.MyEventListener" />
<flowable:eventListener delegateExpression="${testEventListener}" events="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" />
</extensionElements>

...

</process>

对于与实体相关的事件,也可以向流程定义添加监听器,仅在某实体类型的实体事件发生时得到通知。下面的片段展示如何实现。它可以用于所有实体事件(第一个示例)或仅特定事件类型(第二个示例)。

<process id="testEventListeners">
<extensionElements>
<flowable:eventListener class="org.flowable.engine.test.MyEventListener" entityType="task" />
<flowable:eventListener delegateExpression="${testEventListener}" events="ENTITY_CREATED" entityType="task" />
</extensionElements>

...

</process>

entityType 的受支持取值为:attachment、comment、execution、identity-link、job、process-instance、process-definition、task。

抛出 BPMN 事件的监听器​

处理被派发事件的另一种方式是抛出一个 BPMN 事件。请记住,只有在某些类型的 Flowable 事件下抛出 BPMN 事件才有意义。例如,在流程实例被删除时抛出 BPMN 事件会导致错误。下面的片段展示如何在流程实例内部抛出信号、向外部流程抛出信号(全局)、在流程实例内部抛出消息事件以及在流程实例内部抛出错误事件。这里使用的是 throwEvent 属性而非 class 或 delegateExpression,以及一个与所抛出事件类型相关的附加属性。

<process id="testEventListeners">
<extensionElements>
<flowable:eventListener throwEvent="signal" signalName="My signal" events="TASK_ASSIGNED" />
</extensionElements>
</process>

<process id="testEventListeners">
<extensionElements>
<flowable:eventListener throwEvent="globalSignal" signalName="My signal" events="TASK_ASSIGNED" />
</extensionElements>
</process>

<process id="testEventListeners">
<extensionElements>
<flowable:eventListener throwEvent="message" messageName="My message" events="TASK_ASSIGNED" />
</extensionElements>
</process>

<process id="testEventListeners">
<extensionElements>
<flowable:eventListener throwEvent="error" errorCode="123" events="TASK_ASSIGNED" />
</extensionElements>
</process>

如果需要额外逻辑来决定是否抛出 BPMN 事件,可以扩展 Flowable 提供的监听器类。通过在子类中覆写 isValidEvent(FlowableEvent event),可以阻止抛出 BPMN 事件。涉及的类有 org.flowable.engine.test.api.event.SignalThrowingEventListenerTest、org.flowable.engine.impl.bpmn.helper.MessageThrowingEventListener 和 org.flowable.engine.impl.bpmn.helper.ErrorThrowingEventListener。

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

  • 事件监听器只能声明在 process 元素上,作为 extensionElements 的子元素。监听器不能定义在流程中的单个活动上。
  • delegateExpression 中使用的表达式不能访问执行上下文(其他表达式例如网关中的表达式可以)。它们只能引用流程引擎配置 beans 属性中定义的 bean,或在使用 Spring(且 beans 属性不存在时)引用任何实现监听器接口的 spring bean。
  • 使用监听器的 class 属性时,只会创建该类的单个实例。请确保监听器实现不依赖成员字段,或确保可从多线程/上下文安全使用。
  • 当 events 属性中使用了非法事件类型、或使用了非法的 throwEvent 值时,在部署流程定义时会抛出异常(实际上使部署失败)。当提供了非法的 class 或 delegateExecution 值(不存在的类、不存在的 bean 引用或未实现监听器接口的委托)时,在流程启动时(或向该监听器派发该流程定义的第一个有效事件时)会抛出异常。请确保所引用的类位于 classpath 上、且表达式解析为有效实例。

通过 API 派发事件​

我们通过 API 开放了事件派发机制,允许你向引擎中注册的任何监听器派发自定义事件。建议(虽然不强制)只派发类型为 CUSTOM 的 FlowableEvent。派发事件可以使用 RuntimeService 完成:

/**
* Dispatches the given event to any listeners that are registered.
* @param event event to dispatch.
*
* @throws FlowableException if an exception occurs when dispatching the event or
* when the {@link FlowableEventDispatcher} is disabled.
* @throws FlowableIllegalArgumentException when the given event is not suitable for dispatching.
*/
void dispatchEvent(FlowableEvent event);

受支持的事件类型​

下面列出引擎中可能发生的所有事件类型。每个类型对应 org.flowable.common.engine.api.delegate.event.FlowableEventType 中的一个枚举值(身份管理事件则对应 org.flowable.idm.api.event.FlowableIdmEventType)。

受支持的事件

事件名称描述事件类
ENGINE_CREATED该监听器所附着的流程引擎已创建并可用于 API 调用。org.flowable...FlowableEvent
ENGINE_CLOSED该监听器所附着的流程引擎已关闭。对引擎的 API 调用不再可能。org.flowable...FlowableEvent
ENTITY_CREATED一个新实体被创建。新实体包含在事件中。org.flowable...FlowableEntityEvent
ENTITY_INITIALIZED一个新实体已创建并完全初始化。如果在实体创建过程中创建了子实体,此事件会在子实体创建/初始化之后触发,而不同于 ENTITY_CREATE 事件。org.flowable...FlowableEntityEvent
ENTITY_UPDATED一个已有实体被更新。被更新的实体包含在事件中。org.flowable...FlowableEntityEvent
ENTITY_DELETED一个已有实体被删除。被删除的实体包含在事件中。org.flowable...FlowableEntityEvent
ENTITY_SUSPENDED一个已有实体被挂起。被挂起的实体包含在事件中。将对流程定义、流程实例和任务派发。org.flowable...FlowableEntityEvent
ENTITY_ACTIVATED一个已有实体被激活。被激活的实体包含在事件中。将对流程定义、流程实例和任务派发。org.flowable...FlowableEntityEvent
JOB_EXECUTION_SUCCESS一个作业已成功执行。事件包含被执行的作业。org.flowable...FlowableEntityEvent
JOB_EXECUTION_FAILURE作业执行失败。事件包含被执行的作业和异常。org.flowable...FlowableEntityEvent and org.flowable...FlowableExceptionEvent
JOB_RETRIES_DECREMENTED由于作业失败,作业重试次数已递减。事件包含被更新的作业。org.flowable...FlowableEntityEvent
TIMER_SCHEDULED一个定时器作业已创建并被调度在未来某个时间执行。org.flowable...FlowableEntityEvent
TIMER_FIRED一个定时器已触发。事件包含被执行的作业。org.flowable...FlowableEntityEvent
JOB_CANCELED一个作业已被取消。事件包含被取消的作业。作业可通过 API 调用取消、任务完成后关联的边界定时器被取消、在新流程定义部署时取消。org.flowable...FlowableEntityEvent
ACTIVITY_STARTED一个活动开始执行org.flowable...FlowableActivityEvent
ACTIVITY_COMPLETED一个活动成功完成org.flowable...FlowableActivityEvent
ACTIVITY_CANCELLED一个活动即将被取消。活动取消有三种原因(MessageEventSubscriptionEntity、SignalEventSubscriptionEntity、TimerEntity)。org.flowable...FlowableActivityCancelledEvent
ACTIVITY_SIGNALED一个活动收到了信号org.flowable...FlowableSignalEvent
ACTIVITY_MESSAGE_RECEIVED一个活动收到了消息。在活动收到消息之前派发。收到时,根据类型(边界事件或事件子流程启动事件)将为该活动派发 ACTIVITY_SIGNALED 或 ACTIVITY_STARTED。org.flowable...FlowableMessageEvent
ACTIVITY_MESSAGE_WAITING一个活动已创建消息事件订阅并正在等待接收。org.flowable...FlowableMessageEvent
ACTIVITY_MESSAGE_CANCELLED已为其创建消息事件订阅的活动被取消,因此接收该消息将不再触发此特定消息。org.flowable...FlowableMessageEvent
ACTIVITY_ERROR_RECEIVED一个活动已收到错误事件。在错误被活动实际处理之前派发。事件的 activityId 包含对错误处理活动的引用。如果错误成功送达,此事件之后将跟随所涉及活动的 ACTIVITY_SIGNALLED 或 ACTIVITY_COMPLETE 事件。org.flowable...FlowableErrorEvent
UNCAUGHT_BPMN_ERROR一个未捕获的 BPMN 错误被抛出。流程没有针对该特定错误的处理器。事件的 activityId 将为空。org.flowable...FlowableErrorEvent
ACTIVITY_COMPENSATE一个活动即将被补偿。事件包含将为补偿而执行的活动 id。org.flowable...FlowableActivityEvent
MULTI_INSTANCE_ACTIVITY_STARTED一个多实例活动开始执行org.flowable...FlowableMultiInstanceActivityEvent
MULTI_INSTANCE_ACTIVITY_COMPLETED一个多实例活动成功完成org.flowable...FlowableMultiInstanceActivityEvent
MULTI_INSTANCE_ACTIVITY_CANCELLED一个多实例活动即将被取消。活动取消有三种原因(MessageEventSubscriptionEntity、SignalEventSubscriptionEntity、TimerEntity)。org.flowable...FlowableMultiInstanceActivityCancelledEvent
VARIABLE_CREATED一个变量已被创建。事件包含变量名、值及相关的执行和任务(如有)。org.flowable...FlowableVariableEvent
VARIABLE_UPDATED一个已有变量已被更新。事件包含变量名、更新后的值及相关的执行和任务(如有)。org.flowable...FlowableVariableEvent
VARIABLE_DELETED一个已有变量已被删除。事件包含变量名、最后已知值及相关的执行和任务(如有)。org.flowable...FlowableVariableEvent
TASK_ASSIGNED一个任务已被分配给用户。事件包含该任务org.flowable...FlowableEntityEvent
TASK_CREATED一个任务已被创建。此事件在 ENTITY_CREATE 事件之后派发。如果任务是流程的一部分,此事件将在任务监听器执行之前触发。org.flowable...FlowableEntityEvent
TASK_COMPLETED一个任务已被完成。此事件在 ENTITY_DELETE 事件之前派发。如果任务是流程的一部分,此事件将在流程继续之前触发,并跟随一个 ACTIVITY_COMPLETE 事件,指向代表被完成任务的活动。org.flowable...FlowableEntityEvent
TASK_OWNER_CHANGED任务负责人已被更改。此事件在 ENTITY_UPDATE 事件之前派发。org.flowable...FlowableEntityEvent
TASK_PRIORITY_CHANGED任务优先级已被更改。此事件在 ENTITY_UPDATE 事件之前派发。org.flowable...FlowableEntityEvent
TASK_DUEDATE_CHANGED任务截止日期已被更改。此事件在 ENTITY_UPDATE 事件之前派发。org.flowable...FlowableEntityEvent
TASK_NAME_CHANGED任务名称已被更改。此事件在 ENTITY_UPDATE 事件之前派发。org.flowable...FlowableEntityEvent
PROCESS_CREATED一个流程实例已被创建。所有基本属性已设置,但变量尚未设置。org.flowable...FlowableEntityEvent
PROCESS_STARTED一个流程实例已被启动。在启动先前创建的流程实例时派发。PROCESS_STARTED 事件在关联的 ENTITY_INITIALIZED 事件之后、且在变量设置完成之后派发。org.flowable...FlowableEntityEvent
PROCESS_COMPLETED一个流程已完成,即该流程实例的所有执行都已停止。在最后一个活动的 ACTIVITY_COMPLETED 事件之后派发。当流程实例到达没有任何转移可走的状态时,流程即完成。org.flowable...FlowableEntityEvent
PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT流程通过到达终止结束事件而完成。org.flowable...FlowableProcessTerminatedEvent
PROCESS_CANCELLED一个流程已被取消。在流程实例从运行时删除之前派发。流程实例例如可通过 API 调用 RuntimeService.deleteProcessInstance、调用活动上的中断边界事件等被取消。org.flowable...FlowableCancelledEvent
MEMBERSHIP_CREATED一个用户被加入某个组。事件涉及相关用户和组的 id。此事件类型定义于 org.flowable.idm.api.event.FlowableIdmEventType。org.flowable...FlowableMembershipEvent
MEMBERSHIP_DELETED一个用户被从某个组移除。事件包含涉及的用户和组的 id。此事件类型定义于 org.flowable.idm.api.event.FlowableIdmEventType。org.flowable...FlowableMembershipEvent
MEMBERSHIPS_DELETED所有成员将从某个组移除。此事件在成员被移除之前抛出,因此它们仍可访问。如果一次删除所有成员,出于性能原因不会抛出单个 MEMBERSHIP_DELETED 事件。此事件类型定义于 org.flowable.idm.api.event.FlowableIdmEventType。org.flowable...FlowableMembershipEvent

所有 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 中。

某些事件类型(与实体相关)会暴露目标实体。根据类型或事件的不同,这些实体可能已不能再被更新(例如实体被删除时)。如果可能,请使用事件所暴露的 EngineService 以安全方式与引擎交互。即便如此,你也需要谨慎对待对所派发事件涉及实体的更新/操作。

不会派发与历史相关的实体事件,因为它们都有一个运行时对应物来派发其事件。