当前位置 博文首页 > 攻城狮Chova:工作流引擎详解!工作流开源框架ACtiviti的详细配
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 >
<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 id
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(InputStream inputStream);
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName);
如果不使用配置文件进行配置,就会基于默认创建配置
ProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE)
.setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000")
.setJobExecutorActivate(true)
.buildProcessEngine();
<bean >
这个bean会用来构建ProcessEngine. 有多个类可以用来定义processEngineConfiguration. 这些类对应不同的环境,并设置了对应的默认值:
<bean >
<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 >
<property name="dataSource" ref="dataSource" />
...
</bean>
<bean >
<property name="jndiName" value="java:comp/env/jdbc/activitiDB"/>
</bean>
<?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>
<?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>
<?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>
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时不会使用. 注意这也会引用一些需要把数据保存到历史表中的功能
<beans ... >
<bean >
<!-- ... -->
<property name="databaseSchemaUpdate" value="true" />
<!-- ... -->
</bean>
</beans>
<property name="jobExecutorActivate" value="false" />
<property name="history" value="audit" />
<property name="processDefinitionCacheLimit" value="10" />
这个配置会把默认的HashMap缓存替换成LRU缓存来提供限制. 这个配置的最佳值跟流程定义的总数有关,实际使用中会具体使用多少流程定义也有关
<property name="processDefinitionCache">
<bean />
</property>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
log4j.appender.consoleAppender.layout.ConversionPattern =ProcessDefinitionId=%X{mdcProcessDefinitionID}
executionId=%X{mdcExecutionId}mdcProcessInstanceID=%X{mdcProcessInstanceID} mdcBusinessKey=%X{mdcBusinessKey} %m%n"
当系统进行高风险任务,日志必须严格检查时,这个功能就非常有用,要使用日志分析的情况
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(..) 方法抛出异常时的行为
<bean >
...
<property name="eventListeners">
<list>
<bean />
</list>
</property>
</bean>
<bean >
...
<property name="typedEventListeners">
<map>
<entry key="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" >
<list>
<bean />
</list>
</entry>
</map>
</property>
</bean>
分发事件的顺序是由监听器添加时的顺序决定的
/**
* 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);
<process >
<extensionElements>
<activiti:eventListener />
<activiti:eventListener delegateExpression="${testEventListener}" events="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" />
</extensionElements>
...
</process>
<process >
<extensionElements>
<activiti:eventListener entityType="task" />
<activiti:eventListener delegateExpression="${testEventListener}" events="ENTITY_CREATED" entityType="task" />
</extensionElements>
...
</process>
<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>
/**
* 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);
事件名称 | 事件描述 | 事件类型 |
---|---|---|
ENGINE_CREATED | 监听器监听的流程引擎已经创建,准备好接受API调用 | ActivitiEvent |
ENGINE_CLOSED | 监听器监听的流程引擎已经关闭,不再接受API调用 | ActivitiEvent |
ENTITY_CREATED | 创建了一个新实体,实体包含在事件中 | ActivitiEntityEvent |
ENTITY_INITIALIZED | 创建了一个新实体,初始化也完成了.如果这个实体的创建会包含子实体的创建,这个事件会在子实体都创建/初始化完成后被触发,这是与ENTITY_CREATED的区别 | ActivitiEntityEvent |
ENTITY_UPDATED | 更新了已存在的实体,实体包含在事件中 | ActivitiEntityEvent |
ENTITY_DELETED | 删除了已存在的实体,实体包含在事件中 | ActivitiEntityEvent |
ENTITY_SUSPENDED | 暂停了已存在的实体,实体包含在事件中.会被ProcessDefinitions,ProcessInstances和Tasks抛出 | ActivitiEntityEvent |
ENTITY_ACTIVATED | 激活了已存在的实体,实体包含在事件中.会被ProcessDefinitions,ProcessInstances和Tasks抛出 | ActivitiEntityEvent |
JOB_EXECUTION_SUCCESS | 作业执行成功,job包含在事件中 | ActivitiEntityEvent |
JOB_EXECUTION_FAILURE | 作业执行失败,作业和异常信息包含在事件中 | ActivitiEntityEvent ActivitiExceptionEvent |
JOB_RETRIES_DECREMENTED | 因为作业执行失败,导致重试次数减少.作业包含在事件中 | ActivitiEntityEvent |
TIMER_FIRED | 触发了定时器,job包含在事件中 | ActivitiEntityEvent |
JOB_CANCELED | 取消了一个作业.事件包含取消的作业.作业可以通过API调用取消,任务完成后对应的边界定时器也会取消,在新流程定义发布时也会取消 | ActivitiEntityEvent |
ACTIVITY_STARTED | 一个节点开始执行 | ActivitiActivityEvent |
ACTIVITY_COMPLETED | 一个节点成功结束 | ActivitiActivityEvent |
ACTIVITY_SIGNALED | 一个节点收到了一个信号 | ActivitiSignalEvent |
ACTIVITY_MESSAGE_RECEIVED | 一个节点收到了一个消息.在节点收到消息之前触发,收到后,会触发ACTIVITY_SIGNAL或ACTIVITY_STARTED, 这会根据节点的类型:边界事件,事件子流程开始事件 | ActivitiMessageEvent |
ACTIVITY_ERROR_RECEIVED | 一个节点收到了一个错误事件.在节点实际处理错误之前触发, 事件的activityId对应着处理错误的节点.这个事件后续会是ACTIVITY_SIGNALLED或ACTIVITY_COMPLETE, 如果错误发送成功的话 | ActivitiErrorEvent |
UNCAUGHT_BPMN_ERROR | 抛出了未捕获的BPMN错误.流程没有提供针对这个错误的处理器.事件的activityId为空 | ActivitiErrorEvent |
ACTIVITY_COMPENSATE | 一个节点将要被补偿.事件包含了将要执行补偿的节点id | ActivitiActivityEvent |
VARIABLE_CREATED | 创建了一个变量.事件包含变量名,变量值和对应的分支或任务(如果存在) | ActivitiVariableEvent |
VARIABLE_UPDATED | 更新了一个变量.事件包含变量名,变量值和对应的分支或任务(如果存在) | ActivitiVariableEvent |
VARIABLE_DELETED | 删除了一个变量.事件包含变量名,变量值和对应的分支或任务(如果存在) |