写点什么

工作流引擎使用详解!工作流框架 Activiti 的详细配置以及安装使用

发布于: 2021 年 05 月 27 日
工作流引擎使用详解!工作流框架Activiti的详细配置以及安装使用

创建 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 idProcessEngineConfiguration.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

  • 删除 dbProperties dataSource 两个 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>
复制代码


  • 类似的配置有 knowledgeBaseCacheLimit knowledgeBaseCache, 它们是配置规则缓存的.只有流程中使用规则任务时才用

日志

  • 从 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,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 抛出到外部流程(全局),在流程实例中抛出一个消息事件,在流程实例中抛出一个错误事件.除了使用 class delegateExpression, 还使用了 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 使用事件机制的方法,允许触发定义在引擎中的任何自定义事件

  • 建议只触发类型为 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 中的一个枚举值



  • 引擎内部所有 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 来以安全的方式来操作引擎.即使如此,也要小心的对事件对应的实体进行更新,操作

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

发布于: 2021 年 05 月 27 日阅读数: 813
用户头像

一位攻城狮的自我修养 2021.04.06 加入

分享技术干货,面试题和攻城狮故事。 你的关注支持是我持续进步的最大动力! https://github.com/ChovaVea

评论

发布
暂无评论
工作流引擎使用详解!工作流框架Activiti的详细配置以及安装使用