1. 程式人生 > >Activiti入門教程四(自定義Activiti命令攔截器)

Activiti入門教程四(自定義Activiti命令攔截器)

     上一篇部落格中在末尾提到了自定義屬於自己的引擎配置,然後自定義一個類,直接繼承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>
     我們看到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;"> 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>

     效果如下