什么是命令模式?

大都很熟悉的设计模式,此问题不在本文介绍范围内。

activiti中的命令模式

activiti使用命令模式作为基础开发模型。把每个操作都封装为一个命令,降低代码的耦合度,避免臃肿的大类的出现。

activiti是怎样运用的命令模式?

相信看activiti手册的都会看到这张图:

这张图描述了ProcessEngine与XXXservice的关系。而XXXService提供了执行流程的所有方法。XXXService的每个方法都执行对应一个cmd。

如启动流程方法:

RuntimeServiceImpl.startProcessInstanceByKey

 public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables) {return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, variables));}

StartProcessInstanceCmd:就为启动流程的命令,里面为启动流程的相关逻辑代码。

上面是执行的典型例子,下面看是如何执行的Cmd呢?

先看XXXService的结构

commandExecutor:从名字可以看出,命令执行器,它提供一个执行命令的方法execute。

不难看出,commandExecutor是命令执行的关键。

看CommnadExecutor的结构图:

下面将从命令环境的初始化到命令执行完的整个过程看看。

以与Spring结合为例

1。初始化命令执行环境:

在ProcessEngineConfigurationImpl的初始化方法中初始化命令执行环境:

protected void init() {initHistoryLevel();initExpressionManager();initVariableTypes();initBeans();initFormEngines();initFormTypes();initScriptingEngines();initBusinessCalendarManager();initCommandContextFactory();initTransactionContextFactory();initCommandExecutors();initServices();initIdGenerator();initDeployers();initJobExecutor();initMailScanner();initDataSource();initTransactionFactory();initSqlSessionFactory();initSessionFactories();initJpa();initDelegateInterceptor();initEventHandlers();}
protected void initCommandExecutors() {initActualCommandExecutor();initCommandInterceptorsTxRequired();initCommandExecutorTxRequired();initCommandInterceptorsTxRequiresNew();initCommandExecutorTxRequiresNew();}

a. 初始化CommandExecutorImpl

protected void initActualCommandExecutor() {actualCommandExecutor = new CommandExecutorImpl();}

b.初始化命令拦截器

protected void initCommandInterceptorsTxRequired() {if (commandInterceptorsTxRequired==null) {if (customPreCommandInterceptorsTxRequired!=null) {commandInterceptorsTxRequired = new ArrayList<CommandInterceptor>(customPreCommandInterceptorsTxRequired);} else {commandInterceptorsTxRequired = new ArrayList<CommandInterceptor>();}commandInterceptorsTxRequired.addAll(getDefaultCommandInterceptorsTxRequired());if (customPostCommandInterceptorsTxRequired!=null) {commandInterceptorsTxRequired.addAll(customPostCommandInterceptorsTxRequired);}commandInterceptorsTxRequired.add(actualCommandExecutor);}}

看SpringProcessEngineConfiguration实现了ProcessEngineConfigurationImpl的getDefaultCommandInterceptorsTxRequired

将LogInterceptor、SpringTransactionInterceptor和CommandContextInterceptor都添加到命令列表中

protected Collection< ? extends CommandInterceptor> getDefaultCommandInterceptorsTxRequired() {if (transactionManager==null) {throw new ActivitiException("transactionManager is required property for SpringProcessEngineConfiguration, use "+StandaloneProcessEngineConfiguration.class.getName()+" otherwise");}List<CommandInterceptor> defaultCommandInterceptorsTxRequired = new ArrayList<CommandInterceptor>();defaultCommandInterceptorsTxRequired.add(new LogInterceptor());defaultCommandInterceptorsTxRequired.add(new SpringTransactionInterceptor(transactionManager, TransactionTemplate.PROPAGATION_REQUIRED));CommandContextInterceptor commandContextInterceptor = new CommandContextInterceptor(commandContextFactory, this);defaultCommandInterceptorsTxRequired.add(commandContextInterceptor);return defaultCommandInterceptorsTxRequired;}

依次设置拦截器的下一个拦截器是谁,在执行的过程中,按顺序执行的拦截器。这里将LogInterceptor作为第一个拦截器。

protected void initCommandExecutorTxRequired() {if (commandExecutorTxRequired==null) {commandExecutorTxRequired = initInterceptorChain(commandInterceptorsTxRequired);}}
protected 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);}

从以上代码可以看出,一共添加了四个拦截器,分别为:LogInterceptor、SpringTransactionInterceptor、CommandContextInterceptor和CommandExecutorImpl

protected void initCommandInterceptorsTxRequiresNew() {if (commandInterceptorsTxRequiresNew==null) {if (customPreCommandInterceptorsTxRequiresNew!=null) {commandInterceptorsTxRequiresNew = new ArrayList<CommandInterceptor>(customPreCommandInterceptorsTxRequiresNew);} else {commandInterceptorsTxRequiresNew = new ArrayList<CommandInterceptor>();}commandInterceptorsTxRequiresNew.addAll(getDefaultCommandInterceptorsTxRequiresNew());if (customPostCommandInterceptorsTxRequiresNew!=null) {commandInterceptorsTxRequiresNew.addAll(customPostCommandInterceptorsTxRequiresNew);}commandInterceptorsTxRequiresNew.add(actualCommandExecutor);}}
protected void initCommandExecutorTxRequiresNew() {if (commandExecutorTxRequiresNew==null) {commandExecutorTxRequiresNew = initInterceptorChain(commandInterceptorsTxRequiresNew);}}

2.初始化Services,将CommandExecutor对象赋值给Service,这里的CommandExecutor为LogInterceptor。

protected void initServices() {initService(repositoryService);initService(runtimeService);initService(historyService);initService(identityService);initService(taskService);initService(formService);initService(managementService);}protected void initService(Object service) {if (service instanceof ServiceImpl) {((ServiceImpl)service).setCommandExecutor(commandExecutorTxRequired);}}

3.以启动流程为例,看Command的执行过程

a.调用RuntimeServcie的启动流程方法:

public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables) {return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, variables));}

b.从上面初始化过程可知,此时的commandExecutor为LogInterceptor,即执行LogInterceptor的execute方法

public <T> T execute(Command<T> command) {log.fine("                                                                                                    ");log.fine("--- starting " + ClassNameUtil.getClassNameWithoutPackage(command) + " --------------------------------------------------------");try {return next.execute(command);} finally {log.fine("--- " + ClassNameUtil.getClassNameWithoutPackage(command) + " finished --------------------------------------------------------");log.fine("                                                                                                    ");}}

c.从上面初始化过程可知,LogInterceptor的next为SpringTransactionInterceptor,即执行SpringTransactionInterceptor的execute方法(SpringTransactionInterceptor的作用是进行事务管理)

public class SpringTransactionInterceptor extends CommandInterceptor {protected PlatformTransactionManager transactionManager;protected int transactionPropagation;public SpringTransactionInterceptor(PlatformTransactionManager transactionManager, int transactionPropagation) {this.transactionManager = transactionManager;this.transactionPropagation = transactionPropagation;}@SuppressWarnings("unchecked")public <T> T execute(final Command<T> command) {TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);transactionTemplate.setPropagationBehavior(transactionPropagation);T result = (T) transactionTemplate.execute(new TransactionCallback() {public Object doInTransaction(TransactionStatus status) {return next.execute(command);}});return result;}
}

d.从上面的初始化过程可知,SpringTransactionInterceptor的next为CommandContextInterceptor,这个CommnadContextInterceptor很关键,系统中的命令上下文就是在这里初始化并传入到Cmd的。命令上下文保存了Cmd执行时不可缺少的如持久化需要的session等重要的对象。非常重要。

public <T> T execute(Command<T> command) {CommandContext context = commandContextFactory.createCommandContext(command);try {Context.setCommandContext(context);Context.setProcessEngineConfiguration(processEngineConfiguration);return next.execute(command);} catch (Exception e) {context.exception(e);} finally {try {context.close();} finally {Context.removeCommandContext();Context.removeProcessEngineConfiguration();}}return null;}

e.从上面的初始化过程可知,CommandContextInterceptor的next为CommnadExecutorImpl

public class CommandExecutorImpl extends CommandInterceptor {public <T> T execute(Command<T> command) {return command.execute(Context.getCommandContext());}
}

e.执行cmd的execute方法

此时执行完毕。

activiti源码学习之命令模式相关推荐

  1. android 指令模式,Android 源码中的命令模式

    原标题:Android 源码中的命令模式 (点击上方公众号,可快速关注) 来源:伯乐在线专栏作者 - PleaseCallMeCoder 链接:http://android.jobbole.com/8 ...

  2. ejabberd源码学习——方法注册模式

    什么叫方法注册模式? 简言之,就是在方法被调用之前,先将方法名与调用此方法的触发条件的关键字建立一种映射关系,当指定的触发条件成立时,相应的方法则将会被调用.称之为方法注册模式,实乃一家之言,关键囿于 ...

  3. RocketMQ源码学习

    RocketMQ源码学习 文章目录 RocketMQ源码学习 Producer 是怎么将消息发送至 Broker 的? 同步发送 异步发送 队列选择器 事务消息 原理 Broker 是怎么处理客户端发 ...

  4. PostgreSQL源码学习(1)--PG13代码结构

    PostgreSQL源码学习(1)–PG13代码结构 PostgreSQL代码结构 Bootstrap:用于支持Bootstrap运行模式,该模式主要用来创建初始的模板数据库. Main:主程序模块, ...

  5. 第八课 k8s源码学习和二次开发原理篇-KubeBuilder使用和Controller-runtime原理

    第八课 k8s源码学习和二次开发原理篇-KubeBuilder使用和Controller-runtime原理 tags: k8s 源码学习 categories: 源码学习 二次开发 文章目录 第八课 ...

  6. Spring源码深度分析一-Spring前世今生以及源码学习路线图

    大家好,我是王老狮,今天开始开新坑.作为JAVA程序员,Spring基本上是必备的技能,也是面试经常考核的技能,特别是大厂,Spring源码基本是必问的题目.但是很多同学看到源码就头疼,根本不知道源码 ...

  7. Opencascade源码学习之模型算法_TKO模块文件介绍

    Opencascade源码学习之模型数据_TKO模块文件介绍 1.TKO 1.BOPAlgo 2.BOPDS 3.BOPTools 4.BRepAlgoAPI 5.IntTools 1.TKO 1.B ...

  8. Hadoop HDFS源码学习之NameNode部分

    NameNode源码学习 文章目录 NameNode源码学习 一.文件系统目录树(第一关系) 2.1 INode相关类 2.2 快照特性的实现 2.3 FSEditLog类 2.4 FSImage类 ...

  9. 【Mybatis源码学习】概述

    [Mybatis源码学习]概述 1.怎样下载源码 1.1 下载地址 1.2 导入Idea 1.2.1 环境 1.2.2 部署与打包 2.源码架构 2.1 核心流程三大阶段 2.1.1 初始化 2.1. ...

最新文章

  1. Python训练营2021:构建8个真实世界的Python项目
  2. 算法导论中求解时间复杂度的三种方法
  3. BOOL,int,float,指针变量 与“零值”比较
  4. 使用VisualSVN Server自动发布站点
  5. leetcode279. 完全平方数(动态规划)
  6. 图文并茂带你迅速了解本科、硕士、博士的区别
  7. web前端面试高频考点——Vue面试题
  8. Matlab线性规划实例
  9. Kinect:少年你步履蹒跚是不是没睡好
  10. 为什么能上QQ不能打开网页
  11. 2 简单使用原形工具Axure RP
  12. 14种旅游消费陷阱警示录
  13. 如何关闭Internet Explorer 增强的安全配置
  14. 如何使用AD账号登录腾讯企业邮箱?
  15. Python中strip函数几种用法
  16. TimingWheel 令人拍案叫绝的设计
  17. 魅族mx6 原生android,苹果和谷歌都要向它学习!看外媒如何评价魅族MX6
  18. cnn keras 实现_在iOS应用中实现Keras CNN
  19. 如何利用GHOST进行全盘的文件备份
  20. 《HBase 不睡觉》第一章 - 初识 HBase

热门文章

  1. 人人都是产品经理总结 第三章2
  2. java中变量 关键字_基于java的voliate关键字详解
  3. 以吃货联盟初级改版为例,(面向对象初级程序设计模拟网上点餐控制台程序(第一版未使用工具辅助类)。
  4. React 组件设计指南
  5. 如何利用英文翻译器在线语音翻译英文
  6. 华为荣耀8X刷鸿蒙系统固件包,华为荣耀8X刷机教程_华为荣耀8X三键强刷官方系统包...
  7. 举个程序员年终总结大纲的例子
  8. PS怎么做流线光效人物动图效果
  9. 不良资产债转股 防范与对策齐飞
  10. 华为手机显示碎片整理图标