Activiti入門教程四(自定義Activiti命令攔截器)
阿新 • • 發佈:2019-02-10
上一篇部落格中在末尾提到了自定義屬於自己的引擎配置,然後自定義一個類,直接繼承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()方法
我們看到init()方法,初始化了很多操作,其中就有我們的 initCommandExecutors(),新增攔截器的操作,那麼什麼時候攔截器起作用呢?我們接著來看一下 return new ProcessEngineImpl(this)方法的實現操作<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>
可以看到在這個方法中,例項化了很多引擎物件,關鍵的一句在於 commandExecutor.execute(new SchemaOperationsProcessEngineBuild()),該語句就觸發了攔截器操作,通過責任鏈來執行我們的攔截器。
上面講述了攔截器的執行時機,下面就來自定義一個攔截器
攔截器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>
攔截器B
<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>
效果如下