Activiti之命令拦截器

来源:互联网 发布:软件企业两免三减半 编辑:程序博客网 时间:2024/06/04 01:29
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、调用命令拦截器执行

原创粉丝点击