Activiti核心架構之職責鏈與命令模式

衣舞晨風發表於2017-06-26

Activiti核心的骨架是:命令模式+職責鏈
本文的程式碼版本:activiti 5.22

一、職責鏈

1、什麼是職責鏈模式

http://blog.csdn.net/jiankunking/article/details/50443294

2、Activiti中職責鏈初始化

     流程初始化流程引擎的時候會初始化很多資訊,具體如下:

protected void init() {
    initConfigurators();
    configuratorsBeforeInit();
    initProcessDiagramGenerator();
    initHistoryLevel();
    initExpressionManager();
    initDataSource();
    initVariableTypes();
    initBeans();
    initFormEngines();
    initFormTypes();
    initScriptingEngines();
    initClock();
    initBusinessCalendarManager();
    initCommandContextFactory();
    initTransactionContextFactory();
    initCommandExecutors();
    initServices();
    initIdGenerator();
    initDeployers();
    initJobHandlers();
    initJobExecutor();
    initAsyncExecutor();
    initTransactionFactory();
    initSqlSessionFactory();
    initSessionFactories();
    initJpa();
    initDelegateInterceptor();
    initEventHandlers();
    initFailedJobCommandFactory();
    initEventDispatcher();
    initProcessValidator();
    initDatabaseEventLogging();
    configuratorsAfterInit();
  }

     由於本文主要探究:職責鏈與命令模式,所以這裡只需要關注initCommandExecutors()即可,在該方法中會進行如下初始化:

protected void initCommandExecutors() {
    //初始化命令上下文
    initDefaultCommandConfig();
    initSchemaCommandConfig();
    //初始化CommandInvoker
    initCommandInvoker();
    //初始化命令攔截器
    //預設會新增LogInterceptor、TransactionInterceptor、CommandContextInterceptor、CommandInterceptor攔截器
    initCommandInterceptors();
    //初始化命令執行器
    //先初始化攔截器之間的指向關係,並獲取到職責鏈的第一個元素first
    //根據CommandConfig與first來初始化CommandExecutorImpl類的例項
    initCommandExecutor();
  }

     後面三個方法具體程式碼如下:

protected List<CommandInterceptor> customPreCommandInterceptors;
protected List<CommandInterceptor> customPostCommandInterceptors;
protected void initCommandInvoker() {
    if (commandInvoker==null) {
      commandInvoker = new CommandInvoker();
    }
  }
protected void initCommandInterceptors() {
    if (commandInterceptors==null) {
      commandInterceptors = new ArrayList<CommandInterceptor>();
      if (customPreCommandInterceptors!=null) {
        commandInterceptors.addAll(customPreCommandInterceptors);
      }
      commandInterceptors.addAll(getDefaultCommandInterceptors());
      if (customPostCommandInterceptors!=null) {
        commandInterceptors.addAll(customPostCommandInterceptors);
      }
      //命令呼叫器,攔截器最後的一個,為呼叫具體的命令
      commandInterceptors.add(commandInvoker);
    }
  }
protected void initCommandExecutor() {
    if (commandExecutor==null) {
      CommandInterceptor first = initInterceptorChain(commandInterceptors);
      commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
    }
  }

     方法之間的呼叫關係及初始化了哪些資訊如下圖所示:
這裡寫圖片描述

     最終命令攔截器鏈就是:
customPreCommandInterceptors->LogInterceptor->TransactionInterceptor->CommandContextInterceptor->customPostCommandInterceptors->commandInvoker

注意:commandInvoker是CommandInterceptor的例項,即最後攔截的是具體命令的執行。

     在初始化過程中主要用到幾個介面結構如下:
這裡寫圖片描述

3、自定義Activiti命令攔截器

     通過上面兩部分大家應該清楚了,activiti職責鏈:是在哪?如何初始化?這個兩個問題了。
     那麼我們應該如何自定義一個攔截器,並指定其在職責鏈中的位置呢?
其實,很簡單:

1、自定義攔截器

public class InterceptorTest extends AbstractCommandInterceptor {
    @Override
    public <T> T execute(CommandConfig config, Command<T> command) {
        //輸出字串和命令
        System.out.println("this is InterceptorTest----->" + command.getClass().getName());
        //然後讓職責鏈中的下一個請求處理者處理命令
        return next.execute(config, command);
    }
}

2、繼承ProcessEngineConfigurationImpl根據需要重寫其中的方法

public class MyProcessEngineConfiguration extends ProcessEngineConfigurationImpl {
    @Override
    protected CommandInterceptor createTransactionInterceptor() {
        // 事務攔截器 在activiti預設初始化的時候是空的
        // 此處返回自定義攔截器InterceptorTest2
        return new InterceptorTest2();
    }
    @Override
    protected Collection<? extends CommandInterceptor> getDefaultCommandInterceptors() {
        //通過重寫父類ProcessEngineConfigurationImpl中的getDefaultCommandInterceptors方法
        //可以自定義攔截器的位置
        //以及新增哪一些攔截器
        List<CommandInterceptor> interceptors = new ArrayList<>();
        interceptors.add(new LogInterceptor());
        CommandInterceptor transactionInterceptor = createTransactionInterceptor();
        if(transactionInterceptor!=null) {
            interceptors.add(transactionInterceptor);
        }
        interceptors.add(new InterceptorTest());
        interceptors.add(new CommandContextInterceptor(commandContextFactory,this));
        return interceptors;
    }
}

3、在配置檔案中注入

<bean id="processEngineConfiguration" class="com.bpm.example.test.MyProcessEngineConfiguration">
        <property name="jdbcUrl" value="jdbc:mysql://10.10.10.10:3306/activiti-test?useUnicode=true&amp;characterEncoding=utf8" />
        <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="false" />
        <!--<property name="mailServerHost" value="mail.my-corp.com" />-->
        <!--<property name="mailServerPort" value="5025" />-->
    </bean>

二、命令模式

1、什麼是命令模式

http://blog.csdn.net/jiankunking/article/details/50767837

2、Activiti中命令模式的使用

1、Command(定義命令的介面,宣告執行的方法)
與標準的Command模式不同之處,就是execute方法中增加了CommandContext資訊,這個類可以說是執行命令的上下文

public interface Command <T> {
  T execute(CommandContext commandContext);
}

2、CommandExecutor(命令執行器,用於執行命令)
其中CommandConfig是命令的配置

/**
 * The command executor for internal usage.
 * 
 * @author Tom Baeyens
 */
public interface CommandExecutor {

  /**
   * @return the default {@link CommandConfig}, used if none is provided.
   */
  CommandConfig getDefaultConfig();

  /**
   * Execute a command with the specified {@link CommandConfig}.
   */
  <T> T execute(CommandConfig config, Command<T> command);

  /**
   * Execute a command with the default {@link CommandConfig}.
   */
  <T> T execute(Command<T> command);

}

3、ServiceImpl類
所有的服務類繼承這個,其實就一個作用,持有CommandExecutor類,這個類是命令的傳送者(類似於命令模式一文中的:電視遙控器)。

public class ServiceImpl {

    protected ProcessEngineConfigurationImpl processEngineConfiguration;

    public ServiceImpl() {

    }

    public ServiceImpl(ProcessEngineConfigurationImpl processEngineConfiguration) {
        this.processEngineConfiguration = processEngineConfiguration;
    }

  protected CommandExecutor commandExecutor;

  public CommandExecutor getCommandExecutor() {
    return commandExecutor;
  }

  public void setCommandExecutor(CommandExecutor commandExecutor) {
    this.commandExecutor = commandExecutor;
  }
}

簡單梳理一下:
   Service實現服務的其中一個標準方法是在具體服務中呼叫commandExecutor.execute(new command())(這裡的command是具體的命令)。其執行步驟就是命令執行器commandExecutor.execute呼叫了其內部變數CommandInterceptor first(第一個命令攔截器)的execute方法(加上了引數commandConfig)。
   CommandInterceptor類中包含了一個CommandInterceptor物件next,用於指向下一個CommandInterceptor,在攔截器的execute方法中,只需要完成其對應的相關操作,然後執行一下next.execute(commandConfig,command),就可以很簡單的將命令傳遞給下一個命令攔截器,然後在最後一個攔截器中執行command.execute(),呼叫這個命令最終要實現的內容就行了。

本文參考:http://www.cnblogs.com/lighten/p/5863102.html

本文demo:https://github.com/jiankunking/bpm_demo

作者:jiankunking 出處:http://blog.csdn.net/jiankunking

相關文章