概述
Activiti流程引擎配置
流程引擎配置类的作用
ProcessEngineConfiguration
- 查找并解析xml配置文件activiti.cfg.xml
- 提供多个静态方法创建配置对象
- 实现几个基于不同场景的子类,配置方式灵活
activiti.cfg.xml
静态方法创建配置对象
多个子类适配不同场景
ProcessEngineConfiguration 类
- ProcessEngineConfigurationImpl 它不是一个实现类是一个抽象类,配置ProcessEngineConfiguration百分之80的属性和一些get,set方法
- StandloneProcessEngineConfiguration 根据new的方式创建对象,使用java代码调用策略方法
- SpringProcessEngineConfiguration 基于Spring的集成Spring对它的功能扩展数据源扩展,事物扩展定一个了一个事物可以装载的目录
创建流程引擎配置-archetype
创建脚手架
- 工程目录位置 Activiti-boot2/tooling/activiti-archetype-unittest
擎配置-config_samples
创建流程引擎配置-config_samples
createProcessEngineConfigurationFromResourceDefault
- 代码如下
public class ConfigTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigTest.class);
@Test
public void testConfig1() {
ProcessEngineConfiguration configuration = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResourceDefault();
LOGGER.info("configuration = {}", configuration);
}
}
-
日志打印结果如下
09:58:22.914[main][INFO ]Loading XML bean definitions from class path resource [activiti.cfg.xml] ProcessDefinitionId= executionId= mdcProcessInstanceID= mdcBusinessKey= o.s.b.f.x.XmlBeanDefinitionReader.loadBeanDefinitions:316 09:58:23.682[main][INFO ]configuration = org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration@279fedbd ProcessDefinitionId= executionId= mdcProcessInstanceID= mdcBusinessKey= c.ConfigTest.testConfig1:21日志分析如下
createStandaloneInMemProcessEngineConfiguration
代码如下
@Test
public void testConfig2() {
ProcessEngineConfiguration configuration = ProcessEngineConfiguration
.createStandaloneInMemProcessEngineConfiguration();
LOGGER.info("configuration = {}", configuration);
}
打印日志如下
10:15:47.331[main][INFO ]configuration = org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration@78e94dcf ProcessDefinitionId= executionId= mdcProcessInstanceID= mdcBusinessKey= c.ConfigTest.testConfig2:28
日志分析如下
源码分析
createStandaloneInMemProcessEngineConfiguration
ProcessEngineConfiguration
.createStandaloneInMemProcessEngineConfiguration()
-
底层源码分析得到
-
实质上调用了h2数据库
-
不依赖Spring
public class StandaloneInMemProcessEngineConfiguration extends StandaloneProcessEngineConfiguration { public StandaloneInMemProcessEngineConfiguration() { this.databaseSchemaUpdate = "create-drop"; this.jdbcUrl = "jdbc:h2:mem:activiti"; } }
createProcessEngineConfigurationFromResourceDefault
-
点击进入下一层源码
public static ProcessEngineConfiguration createProcessEngineConfigurationFromResourceDefault() { return createProcessEngineConfigurationFromResource("activiti.cfg.xml", "processEngineConfiguration"); }
-
获取classPath下的resource文件
public static ProcessEngineConfiguration parseProcessEngineConfigurationFromResource(String resource, String beanName) { Resource springResource = new ClassPathResource(resource); return parseProcessEngineConfiguration(springResource, beanName); }
-
和SpringBean文件一起组装一起
public static ProcessEngineConfiguration parseProcessEngineConfiguration(Resource springResource, String beanName) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); xmlBeanDefinitionReader.setValidationMode(3); xmlBeanDefinitionReader.loadBeanDefinitions(springResource); ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl)beanFactory.getBean(beanName); processEngineConfiguration.setBeans(new SpringBeanFactoryProxyMap(beanFactory)); return processEngineConfiguration; }
ProcessEngineConfiguration 源码分析
ProcessEngineConfigurationImp是继承ProcessEngineConfiguration类
// false 是不会对数据库做修改的
public static final String DB_SCHEMA_UPDATE_FALSE = "false";
// 启动时候创建销毁的时候销毁
public static final String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";
public static final String DB_SCHEMA_UPDATE_TRUE = "true";
public static final String NO_TENANT_ID = "";
protected String processEngineName = "default";
// 集成邮件的配置
protected String mailServerHost;
protected String mailServerUsername;
protected String mailServerPassword;
// 默认是使用的H2数据库,生产环境默认不推荐使用
this.databaseSchemaUpdate = "false";
this.jdbcDriver = "org.h2.Driver";
this.jdbcUrl = "jdbc:h2:tcp://localhost/~/activiti";
// 生成流程图设置字体
this.xmlEncoding = "UTF-8";
this.defaultCamelContext = "camelContext";
this.activityFontName = "Arial";
this.labelFontName = "Arial";
this.annotationFontName = "Arial";
// 对流程图渲染生成渲染的工具
public ProcessDiagramGenerator getProcessDiagramGenerator() {
return this.processDiagramGenerator;
}
// 对数据库表名生成做配置
this.databaseTablePrefix = "";
最重要的方法
@Override
public ProcessEngine buildProcessEngine() {
init();
ProcessEngineImpl processEngine = new ProcessEngineImpl(this);
// trigger build of Activiti 5 Engine
if (isActiviti5CompatibilityEnabled && activiti5CompatibilityHandler != null) {
Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration());
activiti5CompatibilityHandler.getRawProcessEngine();
}
postProcessEngineInitialisation();
return processEngine;
}
-
init()
public void init() { initConfigurators(); configuratorsBeforeInit(); initProcessDiagramGenerator(); initHistoryLevel(); initExpressionManager(); if (usingRelationalDatabase) { initDataSource(); } initAgendaFactory(); initHelpers(); initVariableTypes(); initBeans(); initFormEngines(); initFormTypes(); initScriptingEngines(); initClock(); initBusinessCalendarManager(); initCommandContextFactory(); initTransactionContextFactory(); initCommandExecutors(); initServices(); initIdGenerator(); initBehaviorFactory(); initListenerFactory(); initBpmnParser(); initProcessDefinitionCache(); initProcessDefinitionInfoCache(); initKnowledgeBaseCache(); initJobHandlers(); initJobManager(); initAsyncExecutor(); initTransactionFactory(); if (usingRelationalDatabase) { initSqlSessionFactory(); } initSessionFactories(); initDataManagers(); initEntityManagers(); initHistoryManager(); initJpa(); initDeployers(); initDelegateInterceptor(); initEventHandlers(); initFailedJobCommandFactory(); initEventDispatcher(); initProcessValidator(); initDatabaseEventLogging(); initActiviti5CompatibilityHandler(); configuratorsAfterInit(); }
SpringProcessEngineConfiguration
数据库配置-dbconfig
数据库配置
-
确实默认配置,使用H2内存数据库
-
配置JDBC属性,使用Mybatis提供的连接池
-
配置DataSource,可自选第三方实现
-
配置JDBC属性使用mybatis提供的连接池
数据原配置
- 配置第三方实现的DataSource
- Druid 数据源连接池
支持的数据库类型
-
配置databaseType
数据库更新策略
- 配置dataSourceSchemaUpdate
数据库配置-dbconfig_code
使用默认数据创建数据源
- Java代码
public class ConfigDBTests {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigDBTests.class);
@Test
public void testConfig1() {
ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
LOGGER.info("cfg = {}", cfg);
ProcessEngine processEngine = cfg.buildProcessEngine(); // 创建引擎
LOGGER.info("获取流程引擎 {}", processEngine.getName());
processEngine.close();
}
}
-
activiti.cfg.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.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration"> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti6unit?useUnicode=true&characterEncoding=utf-8&useSSL=false"/> <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/> <property name="jdbcUsername" value="root"/> <property name="jdbcPassword" value="root123456"/> <property name="databaseSchemaUpdate" value="create-drop"/> <!--避免忽略把这个加上--> <!-- <property name="databaseSchemaUpdate" value="true"/>--><!--这样配置就算数据库里面有表也会执行过去,但是单元测试遗留的脏数据会遗留在库里面--> </bean> </beans>
使用DataSource数据源的方式
- 使用Druid数据源
- JavaTest代码
@Test
public void testConfig2() {
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("activiti_druid.cfg.xml");
LOGGER.info("processEngineConfiguration = {}", processEngineConfiguration);
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
LOGGER.info("获取流程引擎 = {}", processEngine.getName());
processEngine.close();
}
-
activiti_druid.cfg.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.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_"/> <property name="databaseType" value="mysql"/> </bean> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="jdbc:mysql://localhost:3306/activiti6unit?useUnicode=true&characterEncoding=utf-8&useSSL=false"/> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="username" value="root"/> <property name="password" value="root123456"/> <property name="initialSize" value="1"/> <property name="maxActive" value="10"/> <property name="filters" value="stat,sl4j"/> </bean> </beans>
日志记录配置-logging
日志组件的关系级MDC
日志组件
日志记录与MDC
配置开启MDC(Mapped Diagnostic Contexts)
- 默认没有开启,需要手动设置LogMDC.setMDCEnable(true)
- 配置logback.xml日志模板%X{mdcProcessInstanceID}
- 流程只有在执行的过程中出现异常时才会记录MDC信息
配置HistoryLevel
- none:不记录历史流程,性能高,流程结束后不可读取
- activiti:归档流程实例和活动实例,流程变量不同步
- audit: 默认值,在acitviti基础上同步变量值,保存单表属性
- full:性能比较差,记录所有实例和变量细节变化
配置基于DB的事件日志
配置Event Logging
- 实验性的事件记录机制,性能影响较大
- 开启默认记录所有数据的变化过程,表记录快速增长
- 日志内容JSON格式,建议使用mogoDB,Elastic Search
日志记录配置-logging_mdc
java配置测试类
public class ConfigMDCTests {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigMDCTests.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule();
@Test
@Deployment(resources = {"com/imooc/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());
}
}
my-process.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!" />-->
<serviceTask id="someTask" activiti:class="com.imooc.activiti.delegage.MDCErrorDelegage"/>
<sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>
<endEvent id="end"/>
</process>
</definitions>
测试异常类
public class MDCErrorDelegage implements JavaDelegate {
private static final Logger LOGGER = LoggerFactory.getLogger(MDCErrorDelegage.class);
@Override
public void execute(DelegateExecution execution) {
LOGGER.info("run MDCErrorDelegage");
throw new RuntimeException("only test");
}
}
历史记录配置-history-1
Java代码,xml代码如下
- ConfigHistoryLevelTests
public class ConfigHistoryLevelTests {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigHistoryLevelTests.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_history.cfg.xml");
@Test
@Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"})
public void test() {
// 启动流程
startProcessInstance();
// 修改变量
changeVariable();
// 提交表单 task
submitTaskFormData();
// 输出历史内容
// 输出历史活动
showHistoryActivity();
// 输出历史变量
showHistoryVariable();
// 输出历史用户任务
showHistoryTask();
// 输出历史表单
showHistoryForm();
// 输出历史详情
showHistoricDetails();
}
private void showHistoricDetails() {
List<HistoricDetail> historicDetails = activitiRule.getHistoryService()
.createHistoricDetailQuery().listPage(0, 100);
for (HistoricDetail historicDetail : historicDetails) {
LOGGER.info("historicDetail = {}", toString(historicDetail));
}
LOGGER.info("historicDetail.size() = {}", historicDetails.size());
}
private void showHistoryForm() {
List<HistoricDetail> historicDetailForm = activitiRule.getHistoryService()
.createHistoricDetailQuery().listPage(0, 100);
for (HistoricDetail historicDetail : historicDetailForm) {
LOGGER.info("historicDetail = {}", toString(historicDetail));
}
LOGGER.info("historicDetailForm.size = {}", historicDetailForm.size());
}
private void showHistoryTask() {
List<HistoricTaskInstance> historicTaskInstances = activitiRule.getHistoryService()
.createHistoricTaskInstanceQuery().listPage(0, 100);
for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
LOGGER.info("historicTaskInstance = {}", historicTaskInstance);
}
LOGGER.info("historicTaskInstance.size = {}", historicTaskInstances.size());
}
private void showHistoryVariable() {
List<HistoricVariableInstance> historicVariableInstances = activitiRule.getHistoryService()
.createHistoricVariableInstanceQuery()
.listPage(0, 100);
for (HistoricVariableInstance historicVariableInstance : historicVariableInstances) {
LOGGER.info("historicVariableInstance = {}", historicVariableInstance);
}
LOGGER.info("historicVariableInstance.size() = {}", historicVariableInstances.size());
}
private void showHistoryActivity() {
List<HistoricActivityInstance> historicActivityInstances = activitiRule.getHistoryService()
.createHistoricActivityInstanceQuery().listPage(0, 100);
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
LOGGER.info("historicActivityInstance {} =", historicActivityInstance);
}
LOGGER.info("historicActivityInstance.size = {}", historicActivityInstances.size());
}
private void submitTaskFormData() {
Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
HashMap<String, String> properties = Maps.newHashMap();
properties.put("formkey1", "valuef1");
properties.put("formkey2", "valuef2");
activitiRule.getFormService().submitStartFormData(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() {
HashMap<String, Object> params = Maps.newHashMap();
params.put("keyStart1", "value1");
params.put("keyStart2", "value2");
ProcessInstance processInstance = activitiRule.getRuntimeService()
.startProcessInstanceByKey("my-process");
}
static String toString(HistoricDetail historicDetail) {
return ToStringBuilder.reflectionToString(historicDetail, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
-
activiti_history.cfg.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.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration"> <property name="commandInvoker" ref="commandInvoker"/> <!--<property name="history" value="none"/>--> <!--<property name="history" value="activity"/>--> <!--<property name="history" value="audit"/>--> <property name="history" value="none"/> </bean> <bean id="commandInvoker" class="com.imooc.activiti.interceptor.MDCComandInvoker"/> </beans> -
拦截器(MDCComandInvoker)
public class MDCComandInvoker extends DebugCommandInvoker { @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); } } } -
测试结果
事件处理及监听器配置-eventlog
Java代码及xml代码
public class ConfigEventLogTests {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigEventLogTests.class);
@Rule
public ActivitiRule activitiRule = new ActivitiRule("activiti_eventlog.cfg.xml");
@Test
@Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"})
public void test() {
ProcessInstance processInstance = activitiRule.getRuntimeService()
.startProcessInstanceByKey("my-process");
Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
activitiRule.getTaskService().complete(task.getId());
List<EventLogEntry> eventLogEntries = activitiRule.getManagementService()
.getEventLogEntriesByProcessInstanceId(processInstance.getProcessInstanceId());
for (EventLogEntry eventLogEntry : eventLogEntries) {
LOGGER.info("eventLogEntry.type = {},eventLogEntry.data = {}", eventLogEntry.getType(), eventLogEntry.getData());
}
LOGGER.info("eventLogEntries.size = {}", eventLogEntries.size());
}
}
- activiti_eventlog.cfg.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.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<property name="commandInvoker" ref="commandInvoker"/>
<property name="enableDatabaseEventLogging" value="true"/>
</bean>
<bean id="commandInvoker" class="com.imooc.activiti.interceptor.MDCComandInvoker"/>
</beans>
事件处理及监听器配置-eventLinstener-1
监听器原理
- 监听器
- 事件源 :是流程引擎对象
- 事件类型:创建类型
监听器配置方式
配置Listener
- eventListener:监听所有事件派发通知
- typeEventListerners: 监听指定事件类型的通知
- activiti:eventListener:只监听特定流程事件
Activiti的事件监听
相关API
- ActivitiEvent:事件监听
- ActivitiEventListener:监听器(所有类的监听抽象接口)
- ActivitiEventType:事件类型(是一个枚举类型30多个枚举类型)
事件处理及监听器配置-eventLinstener-2
监听器的配置方式
Activiti的事件监听
命令拦截器配置-command-1
命令模式和责任链模式
命令模式
责任链模式
命令拦截器的配置
配置Interceptor
- customPreCommandInterceptors :配置在默认拦截器之前
- customPostCommandInterceptors: 配置在默认拦截器之后
- commandInvoke: 配置最后的拦截器
拦截器的配置方式
-
Java代码
public class ConfigInterceptorTests { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigInterceptorTests.class); @Rule public ActivitiRule activitiRule = new ActivitiRule("activiti_intercptor.cfg.xml"); @Test @Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"}) public void test() { ProcessInstance processInstance = activitiRule.getRuntimeService() .startProcessInstanceByKey("my-process"); Task task = activitiRule.getTaskService().createTaskQuery().singleResult(); activitiRule.getTaskService().complete(task.getId()); } } -
activiti_intercptor.cfg.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.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration"> <property name="commandInvoker" ref="commandInvoker"/> <property name="enableVerboseExecutionTreeLogging" value="false"/><!--记录怎个过程的日志--> <property name="enableDatabaseEventLogging" value="false"/> <property name="customPreCommandInterceptors"> <list> <bean class="com.imooc.activiti.interceptor.DurationCommandInterceptor"/> </list> </property> </bean> <bean id="commandInvoker" class="com.imooc.activiti.interceptor.MDCComandInvoker"/> </beans> -
执行结果
作业执行器配置-job-1
作业执行器的配置
- asyncExecutorActivitate:激活作业执行器
- asyncExecutorXXX :异步执行器属性配置
- asyncExecutor: 异步执行器Bean
自定义线程池ExecutorService
- corePoolSize :核心线程数
- maxPoolSize: 最大线程数
- queueCapacity: 阻塞队列大小
定时开始事件(Timer Start Event)
- timeDate:指定启动时间
- timeDuration:指定持续时间间隔后执行
- timeCycle:R5/P1DT1H指定事件段后期执行
作业执行器配置-job-2
配置自定义线程池
<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>
- activiti_job.cfg.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.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<!-- <property name="commandInvoker" ref="commandInvoker"/>-->
<property name="enableDatabaseEventLogging" value="true"/>
<!--异步激活器-->
<property name="asyncExecutorActivate" value="true"/>
<!--异步执行器-->
<property name="asyncExecutor" ref="asyncExecutor"/>
<!--配置事件监听-->
<property name="eventListeners">
<list>
<bean class="com.imooc.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>
<bean id="commandInvoker" class="com.imooc.activiti.interceptor.MDCComandInvoker"/>
</beans>
-
my-process_job.bpmn20.xml
<process id="my-process"> <!-- <startEvent id="start"/>--> <startEvent id="start"> <timerEventDefinition> <timeCycle>R5/PT10S</timeCycle><!--间隔10s去执行--> </timerEventDefinition> </startEvent> <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/> <!-- <userTask id="someTask" name="Activiti is awesome!" />--> <serviceTask id="someTask" activiti:class="com.imooc.activiti.delegage.MDCErrorDelegage"/> <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/> <endEvent id="end"/> </process> -
ConfigJobTest
public class ConfigJobTests { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigJobTests.class); @Rule public ActivitiRule activitiRule = new ActivitiRule("activiti_job.cfg.xml"); @Test @Deployment(resources = {"com/imooc/activiti/my-process_job.bpmn20.xml"}) public void test() throws InterruptedException { LOGGER.info("start"); List<Job> jobList = activitiRule.getManagementService().createTimerJobQuery().listPage(0, 100); for (Job job : jobList) { LOGGER.info("定时任务 = {},默认重试次数 = {}", job, job.getRetries()); } LOGGER.info("jobList.size() = {}", jobList.size()); Thread.sleep(1000*1000); LOGGER.info("end"); } } -
JobEventListener
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 {}", eventType,event.getProcessInstanceId() ); } } @Override public boolean isFailOnException() { return false; } } -
执行结果
Activiti与spring集成-1
集成Spring配置
相关配置
- 添加pom依赖activit-spring
- 基于Spring的默认配置activiti-content.xml
- Acitiviti核心服务注入Spring
功能特性
- 集成Sping事物管理器
- 定义文件表达式中使用Spring bean
- 自动部署资源文件
单元测试
- 添加pom依赖Spring-test
- 辅助测试Rule:ActivitiRule
- 辅助测试TestCase:SpringActivitiTestCase (早期Junit3的扩展方式)
基于Spring对Activiti的管理
-
ConfigSpringTests
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:activiti-content.xml"}) public class ConfigSpringTests { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigSpringTests.class); @Rule @Autowired public ActivitiRule activitiRule; @Resource private RuntimeService runtimeService; @Resource private TaskService taskService; @Test @Deployment(resources = {"com/imooc/activiti/my-process.bpmn20.xml"}) public void test() { ProcessInstance processInstance = runtimeService .startProcessInstanceByKey("my-process"); assertNotNull(processInstance); Task task = taskService.createTaskQuery().singleResult(); taskService.complete(task.getId()); } } -
activiti-content.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="dataSource" ref="dataSource"/> <!--连接事物管理--> <property name="transactionManager" ref="transactionManager"/> <!--数据源创建格式--> <property name="databaseSchemaUpdate" value="true"/> </bean> <!--新建数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="jdbc:h2:mem:activiti"/> <property name="driverClassName" value="org.h2.Driver"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean> <!--事物管理--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--构造流程引擎对象--> <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration"/> </bean> <!--获取流程引擎对象后把服务暴露给Spring--> <!--基Sping原理--> <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"/> <!--配置ActivityRule,主要是为测试使用的rule--> <bean id="acitvityRule" class="org.activiti.engine.test.ActivitiRule"> <property name="processEngine" ref="processEngine"/> </bean> </beans> -
执行结果
Activiti与spring集成-3
-
my-process_spring.bpmn20.xml
<process id="my-process"> <startEvent id="start"/> <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/> <serviceTask id="someTask" name="Activiti is awsome!"/> <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/> <serviceTask id="hellobean" activiti:expression="${helloBean.sayHello()}"/> <sequenceFlow id="flow3" sourceRef="hellobean" targetRef="end"/> <endEvent id="end"/> </process> -
HelloBean
public class HelloBean {
private static final Logger LOGGER = LoggerFactory.getLogger(HelloBean.class);
public void sayHello() {
LOGGER.info("sayHello");
}
}
- 配置helloBean