Activiti使用手册(1)- 案例与配置
# Activiti使用手册(1)- 案例与配置
# 一、概述
# 二、基本使用
# 2、案例分析
# 1)案例:审批流程模型化
# ①现实生活中的审批
# ②简单的审批流程
# ③Activiti模型分析
# 2)案例:常见的网上购物流程
# ①现实生活的购物流程
# ②购物流程模型化
# ③Activiti模型分析
# 3、上手操作
# 1)设计工作流及协同工作
# ①简单审批流程设计
- 设计一个二级审批流程
- 创建三个不同的用户作为流程参与者
- 参与者协同完成流程
# 三、Activiti配置
# 1、创建流程引擎相关配置
# 1)Activiti6 提供四种方式来配置流程
- 指定目录加载一个资源配置
- 通过流加载一个资源配置
- 独立的引擎配置
- 通过内存数据库构造对象配置
# 2)涉及类
ProcessEngineConfigUration 引擎配置类,作用如下:
- 查找并解析xml配置文件activiti.cfrg.xml
- 提供多个静态方法配置对象
# 3)涉及子类
ProcessEngineConfiguration
**ProcessEngineConfigurationImpl **抽象类配置了ProcessEngineConfiguration的户型
**StandaloneProcessEngineConfiguration **通过new的方式创建对象
**SpringProcessEngineConfiguration **基于spring集成完成扩展
# 4)创建配置对象的静态方法
- 默认路径加载一个资源配置文件构造对象
ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault()
- 指定目录加载一个资源配置文件构造对象
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String)
- 指定目录和修改id类型加载一个资源配置文件构造对象
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String,String)
- 通过流加载一个资源配置文件构造对象
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(InputStream)
- 通过流和修改id类型加载一个资源配置文件构造对象
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(InputStream,String)
- 独立的引擎配置对象
ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration()
- 通过内存数据库构造对象
ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()
# 2、数据库配置
# 1)Activiti6 提供两种方式来配置数据库
- 通过JDBC配置(MyBatis)
- 通过数据库连接池配置(Druid、Dbcp、HikariCP)
# 2)创建数据库配置的方法
- 通过JDBC配置(MyBatis),默认配置
<?xml version="1.0" encoding="UTF-8"?>
<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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti6unit?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true&failOverReadOnly=false" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 通过Druid配置
<?xml version="1.0" encoding="UTF-8"?>
<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.StandaloneInMemProcessEngineConfiguration">
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--是否需要历史数据-->
<property name="dbHistoryUsed" value="true"/>
<!--是否需要用户数据-->
<property name="dbIdentityUsed" value="true"/>
<!--给表加前缀-->
<property name="databaseTablePrefix" value="T_"/>-
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url"
value="jdbc:mysql://127.0.0.1:3306/activiti6unit?useUnicode=true&
characterEncoding=utf8&useSSL=false&autoReconnect=true&
failOverReadOnly=false"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="initialSize" value="2"/>
<property name="maxActive" value="10"/>
<property name="filters" value="stat,slf4j"/>
</bean>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 3)配置数据库更新策略,DatabaseSchemaUpdate
- false:启动时检查数据库版本,发生不匹配抛异常,适用于生产环境
- true:启动时自动检查并更新数据库表,不存在创建,适用与开发环境
- create-drop:启动时创建数据库表结构,结束时删除表结构,适用于测试环境
# 4)附:配置DataBase Type的方法
# 3、日志记录配置
# 1)日志组件的关系及MDC
- 日志组件的关系
- 配置开启MDC
MDC:Mapped Diagnostic Context, 映射诊断环境
MDC使用方法1:LogMDC.setMDCEnabled(true);
当出现异常时会在日志显示流程id等信息
public class ConfigMDCTest {
private static final Logger logger= LoggerFactory.getLogger(ConfigMDCTest.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_mdc.cfg.xml");
@Test
@Deployment(resources = {"com/guosh/activiti/my-process.bpmn20.xml"})
public void test() {
LogMDC.setMDCEnabled(true);
ProcessInstance processInstance = activitiRule
.getRuntimeService()
.startProcessInstanceByKey("my-process");
assertNotNull(processInstance);
Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
assertEquals("Activiti is awesome!", task.getName());
activitiRule.getTaskService().complete(task.getId());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
MDC使用方法2:通过拦截器设置MDC
<?xml version="1.0" encoding="UTF-8"?>
<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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti6unit?
useUnicode=true&characterEncoding=utf8&
useSSL=false&autoReconnect=true&
failOverReadOnly=false" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
<!--自定义拦截每次执行流程都打印流程id-->
<property name="commandInvoker" ref="commandInvoker"/>
</bean>
<bean id="commandInvoker" class="com.guosh.activiti.interceptor.MDCCommandInvoker"/>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MDCCommandInvoker extends DebugCommandInvoker {
private static final Logger logger = LoggerFactory.getLogger(DebugCommandInvoker.class);
@Override
public void executeOperation(Runnable runnable) {
boolean mdcEnabled = LogMDC.isMDCEnabled();
LogMDC.setMDCEnabled(true);
if (runnable instanceof AbstractOperation) {
AbstractOperation operation = (AbstractOperation) runnable;
if (operation.getExecution() != null) {
LogMDC.putMDCExecution(operation.getExecution());
}
}
super.executeOperation(runnable);
LogMDC.clear();
if(!mdcEnabled){
LogMDC.setMDCEnabled(false);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MDC使用方法3:配置logback.xml
日志模板 %X{mdcProcessInstanceId}
记录结果示例:
# 2)配置历史记录日志级别(HistoryLevel)
配置流程结束后的历史记录分级
- none: 不记录历史流程性能高,流程结束后不可读取
- activiti: 归档流程实例,流程变量不同步 (能看到历史内容历史活动)
- audit: 默认值,在activiti基础上同步变量值,保存表单属性 (能看到历史表单,历史详情)
- full: 性能较差,记录所有实例和变量细节变化 (上面基础上能看到详情的变化)
示例操作请跳转至[]
# 3)配置基于DB的事件日志(Event Logging)
注意事项
- 这是实验性的记录机制,性能影响较大(数据库和应用服务器)
- 开启后默认记录所有变化过程,表记录快速增长
- 内容存储格式是基于JSON格式的,适用于MongoDB,ElasticSearch
# 4、历史记录配置
# 1)配置示例
<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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl"
value="jdbc:mysql://127.0.0.1:3306/activiti6unit?useUnicode=true&
characterEncoding=utf8&useSSL=false&
autoReconnect=true&failOverReadOnly=false" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
<!--自定义拦截每次执行流程都打印流程id-->
<property name="commandInvoker" ref="commandInvoker"/>
<!--查看历史的级别-->
<!--所有历史都看不到-->
<!--<property name="history" value="none"/>-->
<!--能查看历史活动历史变量-->
<!--<property name="history" value="activity"/>-->
<!--能查看到所有,但是查看不到数据的修改记录-->
<!--<property name="history" value="audit"/>-->
<property name="history" value="full"/>
</bean>
<bean id="commandInvoker" class="com.guosh.activiti.interceptor.MDCCommandInvoker"/>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 2)代码示例
public class ConfigMDCTest {
private static final Logger logger= LoggerFactory.getLogger(ConfigMDCTest.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_history.cfg.xml");
@Test
@Deployment(resources = {"com/guosh/activiti/my-process.bpmn20.xml"})
public void test() {
//启动流程
startProcessInstance();
//修改变量
changeVariable();
//提交表单task
submitTaskForm();
//输出历史内容
//输出历史活动
showHistoryActivity();
//历史变量
showHistoryVaiable();
//输出历史用户任务
showHistoryTask();
//历史表单详情
showHistoryForm();
//输出历史详情
showHistoryDetail();
}
//输出历史详情
private void showHistoryDetail() {
List<HistoricDetail> historicDetails = activitiRule.getHistoryService()
.createHistoricDetailQuery().list();
for (HistoricDetail historicDetail:historicDetails) {
logger.info("historicDetail = {}",historicDetail);
}
logger.info("historicDetails.size = {}",historicDetails.size());
}
//历史表单详情
private void showHistoryForm() {
List<HistoricDetail> historicDetailsFrom = activitiRule.getHistoryService()
.createHistoricDetailQuery().formProperties().list();
for (HistoricDetail historicDetail:historicDetailsFrom) {
logger.info("historicDetail = {}",historicDetail);
}
logger.info("historicDetailsFrom.size = {}",historicDetailsFrom.size());
}
//输出历史用户任务
private void showHistoryTask() {
List<HistoricTaskInstance> historicTaskInstances = activitiRule
.getHistoryService().createHistoricTaskInstanceQuery().list();
for (HistoricTaskInstance historicTaskInstance:historicTaskInstances) {
logger.info("historicTaskInstance = {}",historicTaskInstance);
}
logger.info("historicTaskInstances.size = {}",historicTaskInstances.size());
}
//历史变量
private void showHistoryVaiable() {
List<HistoricVariableInstance> historicVariableInstances = activitiRule
.getHistoryService().createHistoricVariableInstanceQuery().list();
for (HistoricVariableInstance historicActivityInstance:historicVariableInstances){
logger.info("historicActivityInstance = {}",historicActivityInstance);
}
logger.info("historicVariableInstances.size = {}",historicVariableInstances.size());
}
//输出历史活动
private void showHistoryActivity() {
List<HistoricActivityInstance> historicActivityInstances = activitiRule
.getHistoryService().createHistoricActivityInstanceQuery().list();
for (HistoricActivityInstance historicActivityInstance:historicActivityInstances){
logger.info("historicActivityInstance = {}"
,historicActivityInstance);
}
logger.info("historicActivityInstance.size = {}"
,historicActivityInstances.size());
}
//
//提交表单task
private void submitTaskForm() {
Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
Map<String,String> properties= Maps.newHashMap();
properties.put("formKey1","valuef1");
properties.put("formKey2","valuef2");
activitiRule.getFormService().submitTaskFormData(task.getId(),properties);
}
//修改变量
private void changeVariable() {
List<Execution> executions = activitiRule.getRuntimeService()
.createExecutionQuery().listPage(0, 100);
for (Execution execution:executions) {
logger.info("execution = {}",execution);
}
logger.info("execution.size = {}", executions.size());
String id=executions.iterator().next().getId();
activitiRule.getRuntimeService().setVariable(id,"keyStart1","value1_");
}
//启动流程
private void startProcessInstance() {
Map<String,Object> params= Maps.newHashMap();
params.put("keyStart1","value1");
params.put("keyStart2","value2");
ProcessInstance processInstance = activitiRule.getRuntimeService()
.startProcessInstanceByKey("my-process",params);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# 3)示例结果
# 5、事件处理及监听器配置
- 作用:监听变化 并记录变化日志
- 方法:在XML中配置
enableDatabaseEventLogging
# 1)事件处理配置示例
<?xml version="1.0" encoding="UTF-8"?>
<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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl"
value="jdbc:mysql://127.0.0.1:3306/activiti6unit?useUnicode=true&
characterEncoding=utf8&useSSL=false&
autoReconnect=true&failOverReadOnly=false" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
<!--自定义拦截每次执行流程都打印流程id-->
<property name="commandInvoker" ref="commandInvoker"/>
<!--事件监听器-->
<property name="enableDatabaseEventLogging" value="true"/>
</bean>
<bean id="commandInvoker" class="com.guosh.activiti.interceptor.MDCCommandInvoker"/>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 2)事件处理代码示例
public class ConfigEventLogTest {
private static final Logger logger= LoggerFactory.getLogger(ConfigEventLogTest.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_evenlog.cfg.xml");
@Test
@Deployment(resources = {"com/guosh/activiti/my-process.bpmn20.xml"})
public void test() {
ProcessInstance processInstance = activitiRule.getRuntimeService()
.startProcessInstanceByKey("my-process");
Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
assertEquals("Activiti is awesome!", task.getName());
activitiRule.getTaskService().complete(task.getId());
//根据流程id查询
List<EventLogEntry> envenLogEntrys = activitiRule.getManagementService()
.getEventLogEntriesByProcessInstanceId(processInstance.getId());
for (EventLogEntry eventLogEntry:envenLogEntrys) {
logger.info("eventLogEntry.type = {},eventLogEntry.data = {}"
,eventLogEntry.getType(),eventLogEntry.getData());
}
logger.info("envenLogEntrys.sice = {},eventLogEntry.data = {}"
,envenLogEntrys.size());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 3)事件处理示例结果
# 4)监听器概念
- 事件及监听器原理
- 监听器配置方式
- 配置Listener
- eventListeners:监听所有事件派发通知
- typedEventListeners:监听指定事件类型的通知
- activiti:eventListener:只监听特定的流程定义事件
- 配置Listener
**
- Activiti的事件监听(举例)
- 相关API
- ActivitiEvent:事件对象
- ActivitiEventListener:监听器
- ActivitiEventType:事件类型
# 5)监听器注册方式一
<?xml version="1.0" encoding="UTF-8"?>
<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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti6unit?
useUnicode=true&characterEncoding=utf8&
useSSL=false&autoReconnect=true&
failOverReadOnly=false" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
<!--第一种方式-->
<property name="eventListeners">
<list>
<bean class="com.guosh.activiti.event.ProcessEventListener"/>
</list>
</property>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ProcessEventListener implements ActivitiEventListener {
private static final Logger logger= LoggerFactory
.getLogger(ProcessEventListener.class);
@Override
public void onEvent(ActivitiEvent event) {
ActivitiEventType eventType = event.getType();
//判断如果是流程启动
if(ActivitiEventType.PROCESS_STARTED.equals(eventType)){
logger.info("流程启动 {} \t {}",event.getType(),event.getProcessInstanceId());
}
//流程结束
else if(ActivitiEventType.PROCESS_COMPLETED.equals(eventType)){
logger.info("流程结束 {} \t {}",event.getType(),event.getProcessInstanceId());
}
}
@Override
public boolean isFailOnException() {
return false;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 6)监听器注册方式二
<property name="typedEventListeners">
<map>
<!--流程启动-->
<entry key="PROCESS_STARTED">
<list>
<bean class="com.guosh.activiti.event.ProcessEventListener"/>
</list>
</entry>
</map>
</property>
2
3
4
5
6
7
8
9
10
# 7)自定义监听
public class ConfigEventListenerTest {
private static final Logger logger= LoggerFactory
.getLogger(ConfigEventListenerTest.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_evenlistener.cfg.xml");
@Test
@Deployment(resources = {"com/guosh/activiti/my-process.bpmn20.xml"})
public void test() {
ProcessInstance processInstance = activitiRule.getRuntimeService()
.startProcessInstanceByKey("my-process");
Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
assertEquals("Activiti is awesome!", task.getName());
activitiRule.getTaskService().complete(task.getId());
//发出一个自定义事件
activitiRule.getRuntimeService()
.dispatchEvent(new ActivitiActivityEventImpl(ActivitiEventType.CUSTOM));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CustomEventListener implements ActivitiEventListener {
private static final Logger logger= LoggerFactory.getLogger(CustomEventListener.class);
@Override
public void onEvent(ActivitiEvent event) {
ActivitiEventType eventType = event.getType();
//判断如果是自定义的事件
if(ActivitiEventType.CUSTOM.equals(eventType)){
logger.info("监听到自定义事件 {} \t {}",
event.getType(),event.getProcessInstanceId());
}
}
@Override
public boolean isFailOnException() {
return false;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti6unit?
useUnicode=true&characterEncoding=utf8&
useSSL=false&autoReconnect=true&
failOverReadOnly=false" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
<!--自定义监听事件-->
<property name="eventListeners">
<list>
<bean class="com.guosh.activiti.event.CustomEventListener"/>
</list>
</property>
</bean>
<bean id="commandInvoker" class="com.guosh.activiti.interceptor.MDCCommandInvoker"/>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 8)通过代码注册监听
public class ConfigEventListenerTest {
private static final Logger logger= LoggerFactory
.getLogger(ConfigEventListenerTest.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_evenlistener.cfg.xml");
@Test
@Deployment(resources = {"com/guosh/activiti/my-process.bpmn20.xml"})
public void test() {
activitiRule.getRuntimeService().addEventListener(new CustomEventListener());
ProcessInstance processInstance = activitiRule
.getRuntimeService()
.startProcessInstanceByKey("my-process");
Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
assertEquals("Activiti is awesome!", task.getName());
activitiRule.getTaskService().complete(task.getId());
//通过addEventListener注册
activitiRule.getRuntimeService().addEventListener(new CustomEventListener());
//发出一个自定义事件
activitiRule.getRuntimeService()
.dispatchEvent(new ActivitiActivityEventImpl(ActivitiEventType.CUSTOM));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 9)OnEvent源码
# 6、命令拦截器配置
# 1)命令模式与责任链模式
- 命令模式:“四人帮”编写的经典的23种设计模式之一——行为模式
- 责任链模式:多个拦截器组成的拦截器链
# 2)拦截器的配置方式
- 配置Interceptor
- customPreCommandInterceptors:配置在默认拦截器之前
- customPostCommandInterceptors:配置在默认拦截器之后
- commandInvoker:配置最后的执行器
public class DurationCommandInterceptor extends AbstractCommandInterceptor {
private static final Logger logger = LoggerFactory
.getLogger(DurationCommandInterceptor.class);
@Override
public <T> T execute(CommandConfig config, Command<T> command) {
//取毫秒数
long start =System.currentTimeMillis();
try {
return this.getNext().execute(config,command);
}finally {
long duration = System.currentTimeMillis() - start;
logger.info("{} 执行时长 {} 毫秒",command.getClass().getSimpleName(),duration);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ConfigInterceptorTest {
private static final Logger logger= LoggerFactory.getLogger(ConfigInterceptorTest.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_interceptor.cfg.xml");
@Test
@Deployment(resources = {"com/guosh/activiti/my-process.bpmn20.xml"})
public void test() {
ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");
Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
assertEquals("Activiti is awesome!", task.getName());
activitiRule.getTaskService().complete(task.getId());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti6unit?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true&failOverReadOnly=false" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
<!--拦截器-->
<property name="customPreCommandInterceptors">
<list>
<bean class="com.guosh.activiti.interceptor.DurationCommandInterceptor"/>
</list>
</property>
<property name="customPostCommandInterceptors">
<list>
<bean class="com.guosh.activiti.interceptor.DurationCommandInterceptor"/>
</list>
</property>
<!--能实现mdc同样的效果-->
<property name="enableVerboseExecutionTreeLogging" value="true"/>
<!--自定义拦截每次执行流程都打印流程id-->
<!--<property name="commandInvoker" ref="commandInvoker"/>-->
</bean>
<bean id="commandInvoker" class="com.guosh.activiti.interceptor.MDCCommandInvoker"/>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 3)示例结果
# 4)MDCCommandInvoker
# 7、作业执行器配置
# 1)作业执行器配置
相关配置
- asyncExecutorActivate:激活作业执行器
- asyncExecutorXXX:异步执行器对属性配置(接口)
- asyncExecutor:异步执行器bean
自定义线程池 ExecutorService
- threadNamePrefix:线程池名字前缀
- corePoolSice:核心线程数
- maxPoolSize:最大线程数
- queueCapacity:堵塞队列大小
定时开始事件 Timer Start Event
- timDate:指定启动时间
- timeDuration:指定持续时间间隔后执行
- timCycle:R5/P1DT1H指定事件段后周期执行
# 2)配置自定义线程池
<?xml version="1.0" encoding="UTF-8"?>
<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.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti6unit?
useUnicode=true&characterEncoding=utf8&
useSSL=false&autoReconnect=true&
failOverReadOnly=false" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<!--数据库更新策略-->
<property name="databaseSchemaUpdate" value="true"/>
<!--异步激活器-->
<property name="asyncExecutorActivate" value="true"/>
<!--异步执行器-->
<property name="asyncExecutor" ref="asyncExecutor"/>
<!--监听JOB事件-->
<property name="eventListeners">
<list>
<bean class="com.guosh.activiti.event.JobEventListener"/>
</list>
</property>
</bean>
<bean id="asyncExecutor" class="org.activiti.engine.impl
.asyncexecutor.DefaultAsyncJobExecutor">
<property name="executorService" ref="executorService"/>
</bean>
<!--线程池-->
<bean id="executorService" class="org.springframework.scheduling
.concurrent.ThreadPoolExecutorFactoryBean">
<!--线程池名字前缀-->
<property name="threadNamePrefix" value="activiti-job"/>
<!--核心线程池-->
<property name="corePoolSize" value="5"/>
<!--最大线程数-->
<property name="maxPoolSize" value="20"/>
<!--堵塞队列大小-->
<property name="queueCapacity" value="100"/>
<!--拒绝策略-->
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$AbortPolicy"/>
</property>
</bean>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 3)流程定时任务配置
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.activiti.org/test">
<process id="my-process">
<!--<startEvent id="start" />-->
<startEvent id="start" >
<!--定时启动-->
<timerEventDefinition>
<!--含义执行五次间隔十秒-->
<timeCycle>R5/PT10S</timeCycle>
</timerEventDefinition>
</startEvent>
<sequenceFlow id="flow1" sourceRef="start" targetRef="someTask" />
<userTask id="someTask" name="Activiti is awesome!" />
<sequenceFlow id="flow2" sourceRef="someTask" targetRef="end" />
<endEvent id="end" />
</process>
</definitions>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 4)定时任务事件监听
public class JobEventListener implements ActivitiEventListener {
private static final Logger logger= LoggerFactory.getLogger(JobEventListener.class);
@Override
public void onEvent(ActivitiEvent event) {
ActivitiEventType eventType = event.getType();
String name=eventType.name();
//判断如果是自定义的事件
if(name.startsWith("TIMER")||name.startsWith("JOB")){
logger.info("监听到JOB事件 {} \t {}",
event.getType(),event.getProcessInstanceId());
}
}
@Override
public boolean isFailOnException() {
return false;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ConfigJobTest {
private static final Logger logger= LoggerFactory.getLogger(ConfigJobTest.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_job.cfg.xml");
@Test
@Deployment(resources = {"com/guosh/activiti/my-process_job.bpmn20.xml"})
public void test() throws InterruptedException {
logger.info("start");
//当前有多少个定时任务在执行
List<Job> jobs = activitiRule.getManagementService().createTimerJobQuery().list();
for (Job job:jobs) {
logger.info("定时任务 = {},默认重试次数 = {}",job,job.getRetries());
}
logger.info("jobs.size = {}", jobs.size());
//等待
Thread.sleep(1000*100);
logger.info("end");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 5)示例结果
# 8、Activiti与Spring集成
- 集成Spring配置
- 基于Spring对Activiti管理
- 基于Spring的流程单元测试
# 1)相关配置
- 添加pom依赖activiti-spring
- 基于spring的默认配置 activiti-context.xml (非 activiti.cfg.xml)
- Activiti核心服务注入Spring容器
# 2)功能特征
- 集成spring事物管理器
- 定义文件表达式中使用Spring bean
- 自动部署资源文件
# 3)单元测试
- 添加pom依赖spring-test
- 辅助测试Rule:**ActivitiRule **(推荐)
- 辅助测试TestCase:SpringActrivitiTest(Unit 3)
# 4)配置示例
# ①配置activiti-context.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<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.spring.SpringProcessEngineConfiguration">
<property name="databaseSchemaUpdate" value="true"/>
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--事务管理器-->
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!--流程引擎对象-->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"/>
</bean>
<!--注册服务-->
<bean id="runtimeService"
factory-bean="processEngine" factory-method="getRuntimeService"/>
<bean id="repositoryService"
factory-bean="processEngine" factory-method="getRepositoryService"/>
<bean id="formService"
factory-bean="processEngine" factory-method="getFormService"/>
<bean id="taskService"
factory-bean="processEngine" factory-method="getTaskService"/>
<bean id="historyService"
factory-bean="processEngine" factory-method="getHistoryService"/>
<bean id="activitiRule" class="org.activiti.engine.test.ActivitiRule">
<property name="processEngine" ref="processEngine"/>
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://127.0.0.1:3306/activiti6unit?
useUnicode=true&characterEncoding=utf8&
useSSL=false&autoReconnect=true&
failOverReadOnly=false"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="initialSize" value="2"/>
<property name="maxActive" value="10"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="helloBean" class="com.guosh.activiti.delegate.HelloBean"></bean>
</beans>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# ②测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:activiti-context.xml"})
public class ConfigSpringTest {
private static final Logger logger= LoggerFactory.getLogger(ConfigSpringTest.class);
@Rule
@Autowired
public ActivitiRule activitiRule;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Test
@Deployment(resources = {"com/guosh/activiti/my-process_spring.bpmn20.xml"})
public void test() {
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("my-process");
assertNotNull(processInstance);
Task task = taskService.createTaskQuery().singleResult();
taskService.complete(task.getId());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# ③my-process_spring.bpmn20.xml流程文件
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="my-process">
<startEvent id="start" />
<sequenceFlow id="flow1" sourceRef="start" targetRef="someTask" />
<userTask id="someTask" name="Activiti is awesome!" />
<sequenceFlow id="flow2" sourceRef="someTask" targetRef="helloBean" />
<!--${helloBean.sayHello()}可以调取到自己写到类到方法-->
<serviceTask id="helloBean" activiti:expression="${helloBean.sayHello()}"/>
<sequenceFlow id="flow3" sourceRef="helloBean" targetRef="end" />
<endEvent id="end" />
</process>
</definitions>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 01
- Activiti使用手册(4)- Bpmn2规范06-11
- 02
- linux手动RPM安装gcc,g++06-11