Activiti之命令拦截器

Activiti提供了命令拦截器的功能,外界对Activit流程中各个实例进行操作,实际可以被看作是对数据进行相应的操作,在此过程中,Activiti使用了设计模式中的 命令模式
每一个操作数据库CRUD的操作,均可被看做为一个命令 Command,然后交由命令执行者 CommandExecutor去执行。除此之外,为了能让使用者可以对这些命令进行相应的拦截,Activiti还使用了设计模式中的 职责链模式,使用者可以在其中添加相应的拦截器。

职责模式让多个对象都有机会处理请求,从而避免了请求发送者和请求接收者之间的耦合。这些请求接收者将组成一条链,并沿着这条链传递下去,
直到有一个对象处理这个请求为止,这就形成了一条责任链。


命令设计模式:http://blog.csdn.net/u012867699/article/details/76778699

职责链设计模式:http://blog.csdn.net/u012867699/article/details/76778926



Activiti使用了一个CommandContext类作为命令接收者,该对象维护一系列的Manager对象,这些Manager对象就是J2EE中的DAO对象。
除了命令接收者外,Activiti还使用一系列的CommandInterceptor(命令拦截器),这些命令拦截器扮演命令模式中的命令执行者角色。




Activiti的拦截器,就是结合这两种设计模式,达到拦截器效果的。



所有的命令均需要实现org.activiti.engine.impl.interceptor.Command接口,接口的实现如下:

public interface Command<T> {

  T execute(CommandContext commandContext);

}

execute方法的CommandContext参数,该参数为所有的命令提供了获取数据库、事物管理器、扩展属性等资源。由CommandContextInterceptor提供。


Activiti拦截器的运行过程


通过源码分析一下,Activiti拦截器的执行过程


1、设置拦截器


当初始化流程引擎的时候,会执行下面的方法

org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl

  public ProcessEngine buildProcessEngine() {
    init();
    ProcessEngineImpl processEngine = new ProcessEngineImpl(this);

    postProcessEngineInitialisation();

    return processEngine;
  }

init()方法源码

public void init() {
    initConfigurators();
    configuratorsBeforeInit();
    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();
  }

init方法就是进行初始化,其中initCommanExecutors()方法中有initCommandInterceptors方法是对所有拦截器的初始化。

拦截器列表:

1、前置拦截器

这个需要实现CommandInterceptor接口,并配置到流程定义配置文件中。

2、默认的拦截器:

    1. LogInterceptor日志拦截器,拦截器打印执行的日志。

    2.事务拦截器。

    3.CommandContextInterceptor 命令上下文拦截器:

         流程定义;

        注入命令上下文,命令上下文包括数据只有代码;

       调用明上上下文close方法,执行数据保存

3、后置拦截器

     这个需要实现CommandInterceptor接口,并配置到流程定义配置文件中。

public 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);//调用命令调用者CommandInvoker
    }
  }


其中getDefaultCommandInterceptors方法为设置默认拦截器:

//命令上下文拦截器:流程定义,注入命令上下文

public Collection<? extends CommandInterceptor> getDefaultCommandInterceptors() { 
    List<CommandInterceptor> interceptors = new ArrayList<CommandInterceptor>(); 
    interceptors.add(new LogInterceptor());
    //日志拦截器 
    CommandInterceptor transactionInterceptor = createTransactionInterceptor(); 
    if (transactionInterceptor != null) { 
        interceptors.add(transactionInterceptor);//事物拦截器 
    } 
    if (commandContextFactory != null) {
      interceptors.add(new CommandContextInterceptor(commandContextFactory, this));//命令上下文拦截器 
    } 
    if (transactionContextFactory != null) { 
        interceptors.add(new TransactionContextInterceptor(transactionContextFactory)); 
    } 
    return interceptors; 
}


所有的拦截器都会调用CommandInterceptor


public interface CommandInterceptor {

  <T> T execute(CommandConfig config, Command<T> command);

  CommandInterceptor getNext();

  void setNext(CommandInterceptor next);

}


2、构造拦截器链

CommandInterceptor提供next参数的getter和setter方法,next参数为下一个拦截器的对象的引用。N个拦截器通过next属性关联就形成了一个无限的拦截器链。如何调用第一个拦截器Loginterceptor呢?

ComandExecutor类用来同一执行所有的命令。在initCommandInterceptors初始化拦截器执行完之后,执行方法initCommandExecutor


public void initCommandExecutor() {
    if (commandExecutor == null) {
      CommandInterceptor first = initInterceptorChain(commandInterceptors);
      commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
    }
  }

其中initInterceptorChain方法设置拦截器链,并设置第一个拦截器


public CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {
    if (chain == null || chain.isEmpty()) {
      throw new ActivitiException("invalid command interceptor chain configuration: " + chain);
    }
    for (int i = 0; i < chain.size() - 1; i++) {
      chain.get(i).setNext(chain.get(i + 1));
    }
    return chain.get(0);
  }


3、org.activiti.engine.impl.TaskServiceImpl类中创建任务


  public Task newTask(String taskId) {
    return commandExecutor.execute(new NewTaskCmd(taskId));
  }

CommandExecutor是如何注入的。

在流程引擎初始化的时候 org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl类中initServices方法


  public void initServices() {
    initService(repositoryService);
    initService(runtimeService);
    initService(historyService);
    initService(identityService);
    initService(taskService);
    initService(formService);
    initService(managementService);
    initService(dynamicBpmnService);
  }

  public void initService(Object service) {
    if (service instanceof ServiceImpl) {
      ((ServiceImpl) service).setCommandExecutor(commandExecutor);
    }
  }

这里注入了commandExecutor


参考:ACTIVITI源码研究之命令模式执行 http://blog.csdn.net/u012867699/article/details/76778699

拦截器执行顺序


1、前置拦截器如果存在,执行

2、日志拦截器

3、执行事务拦截器

4、执行CommandContext拦截器。这个拦截器执行数据库持久化。在命令中并不执行数据库持久化,持久化在此拦截器中调用context.close();执行。

5、后置拦截器如果存在,执行

6、调用命令拦截器执行

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值