上一篇博客中在末尾提到了自定义属于自己的引擎配置,然后自定义一个类,直接继承ProcessEngineConfigurationImpl类即可,但必须要实现两个抽象的方法,如下
protected abstract Collection< ? extends CommandInterceptor> getDefaultCommandInterceptorsTxRequired();
protected abstract Collection< ? extends CommandInterceptor> getDefaultCommandInterceptorsTxRequiresNew();
如果英文好的人,应该就看出来了,这就是Activiti中的拦截器,其实拦截器的原理采用了设计模式中的命令模式和责任链模式,关于设计模式请参考职责链模式。
下面就先来通过源码分析,来谈一下Activiti中拦截器的执行过程。
当初始化流程引擎的时候,会执行下面的方法
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;"> public ProcessEngine buildProcessEngine() {
init();
return new ProcessEngineImpl(this);
}</span></span>
下面我们再通过源码来看一下Init()方法
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;">protected void init() {
initHistoryLevel();
initExpressionManager();
initVariableTypes();
initBeans();
initFormEngines();
initFormTypes();
initScriptingEngines();
initBusinessCalendarManager();
initCommandContextFactory();
initTransactionContextFactory();
initCommandExecutors();
initServices();
initIdGenerator();
initDeployers();
initJobExecutor();
initDataSource();
initTransactionFactory();
initSqlSessionFactory();
initSessionFactories();
initJpa();
initDelegateInterceptor();
initEventHandlers();
initFailedJobCommandFactory();
initConfigurators();
}
</span></span>
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;"> public ProcessEngineImpl(ProcessEngineConfigurationImpl processEngineConfiguration) {
this.processEngineConfiguration = processEngineConfiguration;
this.name = processEngineConfiguration.getProcessEngineName();
this.repositoryService = processEngineConfiguration.getRepositoryService();
this.runtimeService = processEngineConfiguration.getRuntimeService();
this.historicDataService = processEngineConfiguration.getHistoryService();
this.identityService = processEngineConfiguration.getIdentityService();
this.taskService = processEngineConfiguration.getTaskService();
this.formService = processEngineConfiguration.getFormService();
this.managementService = processEngineConfiguration.getManagementService();
this.databaseSchemaUpdate = processEngineConfiguration.getDatabaseSchemaUpdate();
this.jobExecutor = processEngineConfiguration.getJobExecutor();
this.commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
this.sessionFactories = processEngineConfiguration.getSessionFactories();
this.transactionContextFactory = processEngineConfiguration.getTransactionContextFactory();
commandExecutor.execute(new SchemaOperationsProcessEngineBuild());
if (name == null) {
log.info("default activiti ProcessEngine created");
} else {
log.info("ProcessEngine {} created", name);
}
ProcessEngines.registerProcessEngine(this);
if ((jobExecutor != null) && (jobExecutor.isAutoActivate())) {
jobExecutor.start();
}
if(processEngineConfiguration.getProcessEngineLifecycleListener() != null)
{
processEngineConfiguration.getProcessEngineLifecycleListener().onProcessEngineBuilt(this);
}
}</span></span>
上面讲述了拦截器的执行时机,下面就来自定义一个拦截器
拦截器A
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;">package org.crazyit.activiti;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandInterceptor;
/**
* 拦截器实现A
*
*/
public class InterceptorA extends CommandInterceptor {
public <T> T execute(Command<T> command) {
// 输出字符串和命令
System.out.println("this is interceptor A "
+ command.getClass().getName());
// 然后让责任链中的下一请求处理者处理命令
return next.execute(command);
}
}
</span></span>
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;">package org.crazyit.activiti;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandInterceptor;
public class InterceptorB extends CommandInterceptor {
@Override
public <T> T execute(Command<T> command) {
// 输出字符串和命令
System.out.println("this is interceptor B "
+ command.getClass().getName());
// 然后让责任链中的下一请求处理者处理命令
return next.execute(command);
}
}
</span></span>
然后自定义流程引擎配置,并在其中添加我们的拦截器即可
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;">package org.crazyit.activiti;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.CommandContextInterceptor;
import org.activiti.engine.impl.interceptor.CommandInterceptor;
import org.activiti.engine.impl.interceptor.LogInterceptor;
/**
* 自定义配置类
*/
public class TestConfiguration extends ProcessEngineConfigurationImpl {
protected Collection<? extends CommandInterceptor> getDefaultCommandInterceptorsTxRequired() {
// 创建一个拦截器集合
List<CommandInterceptor> defaultCommandInterceptorsTxRequired = new ArrayList<CommandInterceptor>();
// 添加自定义拦截器A
defaultCommandInterceptorsTxRequired.add(new InterceptorA());
// 添加系统的拦截器
defaultCommandInterceptorsTxRequired.add(new CommandContextInterceptor(
commandContextFactory, this));
return defaultCommandInterceptorsTxRequired;
}
protected Collection<? extends CommandInterceptor> getDefaultCommandInterceptorsTxRequiresNew() {
// 创建一个拦截器集合
List<CommandInterceptor> defaultCommandInterceptorsTxRequired = new ArrayList<CommandInterceptor>();
// 添加自定义拦截器
defaultCommandInterceptorsTxRequired.add(new InterceptorB());
return defaultCommandInterceptorsTxRequired;
}
}
</span></span>
这样就完成了我们的自定义拦截器的操作,下面来通过XML文件配置相关的数据库信息
<span style="font-family:Comic Sans MS;font-size:18px;"><?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.crazyit.activiti.TestConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="" />
<property name="databaseSchemaUpdate" value="true"></property>
</bean>
</beans>
</span>
最后看一下测试类
<span style="font-family:Comic Sans MS;font-size:18px;">package org.crazyit.activiti;
import java.util.HashMap;
import java.util.Map;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
public class MyConfig {
/**
* @param args
*/
public static void main(String[] args) {
ProcessEngines.getDefaultProcessEngine();
// 创建Activiti配置对象
ProcessEngineConfiguration config = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("my-config.xml");
// 初始化流程引擎
ProcessEngine engine = config.buildProcessEngine();
// 部署一个最简单的流程
engine.getRepositoryService().createDeployment()
.addClasspathResource("bpmn/config.bpmn20.xml").deploy();
// 构建流程参数
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("day", 10);
// 开始流程
engine.getRuntimeService().startProcessInstanceByKey("vacationProcess",
vars);
}
}</span>
效果如下