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、调用命令拦截器执行

Activiti之命令拦截器相关推荐

  1. ef mysql 读写分离_EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一...

    /// ///SQL命令拦截器///主要实现EF的读写分离/// public classCommandInterceptor : DbCommandInterceptor {staticComman ...

  2. Activiti5第七弹,自己实现一个ProcessEngineConfiguration同时自定义拦截器

    首先是我自己定义的MyProcessEngineConfiguration的activiti.cfg.xml文件的内容 <?xml version="1.0"?> &l ...

  3. druid拦截器_CMS基于SpringBoot+Shiro+Mybatis+Druid+layui后台管理系统

    contentManagerSystem后台管理系统 简介 contentManagerSystem,后台管理系统,采用SpringBoot构建整个项目框架,apacheShiro权限验证,mybat ...

  4. springboot + redis + 注解 + 拦截器 实现接口幂等性校验

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 来源:https://www.jianshu.com/p/6189275403ed 一.概念 ...

  5. Flume NG 学习笔记(八)Interceptors(拦截器)测试

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 拦截器主要是对事件的header信息信息操作,要么直接忽略他,要么修改他的数据 一.Event Serializers file ...

  6. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:MVC程序中实体框架的连接恢复和命令拦截...

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第四篇:MVC程序中实体框架的连接恢复和 ...

  7. WebServices中使用cxf开发日志拦截器以及自定义拦截器

    首先下载一个cxf实例,里面包含cxf的jar包.我下的是apache-cxf-2.5.9 1.为什么要设置拦截器? 为了在webservice请求过程中,能动态操作请求和响应数据, CXF设计了拦截 ...

  8. 自定义注解和拦截器,实现接口限流防刷

    我们的目的是在指定时间内,每个用户只能进行秒杀请求指定次数. 首先,定义一个注解 写一个拦截器.就是当执行某个方法之前,将请求截获: (这里实现的只是一个思路,由于StringRedisTemplat ...

  9. Mybatis拦截器 mysql load data local 内存流处理

    Mybatis 拦截器不做解释了,用过的基本都知道,这里用load data local主要是应对大批量数据的处理,提高性能,也支持事务回滚,且不影响其他的DML操作,当然这个操作不要涉及到当前所lo ...

最新文章

  1. 学习《Linux设备模型浅析之设备篇》笔记(三)
  2. 第十九章:集合视图(二十一)
  3. noip模拟题 ----飞
  4. capture one 20 pro中文版
  5. adxl276怎么添加到proteus中_奶粉中的营养强化剂和食品添加剂是怎么一回事?
  6. c语言案例朗读工具源码,C语言编写简单朗读小工具(有源码)
  7. 戴尔服务器t110做系统,戴尔服务器T110
  8. git将本地仓库强制替换掉远程仓库
  9. linux 报错 bash ‘/bin/sh: Syntax error: “(” unexpected
  10. 8位可控加减法电路设计_100以内加减法速算方法,口算速度快一倍
  11. java 类.class_Java 反射之根基 Class 类
  12. 测试开始系列——功能测试用例模板
  13. 基于OpenCV的银行卡号识别系统实现(一)----- 银行卡号识别步骤
  14. 视频Video放器的部分实例方法
  15. 关于使用HTML或JS实现页面重定向的方法
  16. html div旋转45度,CSS动画 - 在每次悬停时进一步旋转45度
  17. 科学计算与数学建模(选择练习)
  18. 跨境电商APP解决方案
  19. 查找微信公众号服务器,墨涩网 - 免插件实现微信公众号搜索连接wordpress网站文章——墨涩网...
  20. 浅谈动态代理和静态代理的底层原理及实现

热门文章

  1. 《Sentinel-2 MSI 用户手册》学习记录
  2. 【重磅干货】H264硬件解码Sample(基于妙算2-G)
  3. 态度支付,如何用聚合支付帮助商家赚钱
  4. ModBusTcp协议(一)
  5. 天天红单app下载安装_天天红单苹果app下载
  6. 抖音快手最新去水印视频下载教程
  7. 3dsmax怎么添加uv坐标_012:多层贴图UVWMAP(UV坐标)技术
  8. word2013安装mathtype7错误‘53‘的解决办法
  9. 糖儿飞教你学C++ Socket网络编程——5.套接字编程步骤与函数
  10. 《惢客创业日记》2019.01.07(周一) 如何破解先有鸡,还是先有蛋?