1.  启动分析

源码是 7.1.0.M6

首先从 ProcessEngineAutoConfiguration 开始

ProcessEngineAutoConfiguration 是activiti-spring-boot-starter 7.1.0.M6自动配置的入口类,在这里主要看 SpringProcessEngineConfiguration

主要是配置了自动部署

最最最重要的是 buildProcessEngine() 方法,将来根据配置构建 ProcessEngine 的时候它就派上用场了

ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault().buildProcessEngine();

下面重点看一下如何构建 ProcessEngine

在父类(ProcessEngineConfigurationImpl)的 buildProcessEngine() 里调用了一个非常重要的方法 init()

可以看到在init()方法里初始化了很多组件,接下来挑几个来重点看一下

initAgendaFactory()

initCommandContextFactory()

new了一个CommandContextFactory,重要的是CommandContextFactory中持有当前processEngineConfiguration的引用

initCommandExecutors()

初始化拦截器interceptor要重点说下,这里构造了一个拦截器链,而且拦截器链的最后是CommandInvoker,并且将第一个拦截器放到CommandExecutor里面,姑且先记下,后面有用到

initServices()

initBehaviorFactory()

在初始化各个组件以后,new了一个ProcessEngineImpl,并将当前的配置 ProcessEngineConfigurationImpl 赋值给它

因此,这个代表流程引擎的ProcessEngine就变成了一个基础的入口类,它提供了对工作流操作的所有服务的访问。

2.  CommandContextInterceptor

在默认的拦截器中有一个 CommandContextInterceptor 特别重要

在其execute()方法中设置上下文CommandContext

  1. 查找栈顶部的元素,如果为空,则新new一个CommandContext,如果不为空,则将获取到的CommandContext的熟悉reused设为true
  2. 将刚才获取到的CommandContext压入栈中
  3. 将当前processEngineConfiguration压入另一个栈中
  4. 调用下一个拦截器

也就是说,每个命令在经过CommandContextInterceptor后都有了自己的上下文

那么,CommandContext中到底有什么呢?继续看

CommandContext中有命令(Command),还有agenda(ActivitiEngineAgenda)

3.  Command

Activiti这里采用命令模式,将操作以及与之相关的信息都封装成命令。

下面以完成任务为例来看一下命令是如何被完成的

前面初始化services的时候说过了,会将创建好的CommandExecutor设置到各个Service中,因此TaskService中commandExecutor的出现就不足为奇了

可以看到,完成任务的时候,直接new了一个CompleteTaskCmd,然后交由commandExecutor去执行

CompleteTaskCmd主要有两个属性:任务ID 和 流程变量

既然命令交给了CommandExecutor执行,那么接下来看下它是如何执行的。

在前面 initCommandExecutor() 的时候我们指定,它其实是 CommandExecutorImpl,并且我们还知道它持有默认的命令配置,以及拦截器链中的第一个拦截器

从代码中可以看到 CommandExecutorImpl#execute() 直接从拦截器链中的第一个拦截器开始往后依次调用。可以预见到,它肯定会经过CommandContextInterceptor,于是在当前请求线程的局部变量中就会有一个栈(Stack),在栈的顶部放了一个CommandContext,在这个CommandContext中有待执行的Command,有processEngineConfiguration,还有agenda。

它这个CommandContext被设计成是每个线程私有的,就是每个线程都有自己的一个CommandContext

在线程局部变量中存放这栈,栈里面放着对象

拦截器链的最后一个拦截器是 CommandInvoker

4.  CommandInvoker

重头戏来了,接下来 CommandInvoker 的每个方法都要仔细看了

可以看到,真正去执行命令是在CommandInvoker中触发的

5.  Agenda

agenda (译:议程,待议事项,议事日程)的意思是“议程”,“会议议程”,“待议事项”

可以把 agenda 想象成是一个会议,首先每个命令请求都有一个 CommandContext,CommandContext里面有Agenda

这样的话,CommandContext 相当于会议室,Agenda 相当于这次会议的议程,就是这次会议要商议的事项有哪些,每个 Operation 相当于一个待议事项,在会议进行期间会不断产生很多新的事项,然后一个一个事项的过,直到所有的事项都处理完了。

也可以把 agenda 想象成线程池,不断有新的任务被丢进线程池,工作线程就不断从工作队列中取任务执行

还是 “会议室 --> 会议 --> 议程 --> 事项 --> 处理事项”更加形象生动

每个命令请求就相当于发起一次会议,会议的目的是处理这次的命令请求。为了开会讨论解决问题,需要有个会议室,然后发起会议,会议上有很多要解决的问题,一个一个解决问题,直到所有问题都被解决,会议结束

每个待议事项都是一个 Runnable 类型的对象,注意别搞混了,Runnable 本身不是线程。我个人猜测,之所以设计成Runnable类型的主要是为了方便异步处理,我们可以配置Activiti的活动是同步还是异步执行,而直接调用Runnable的run()方法就是同步执行,把它放到线程池就是异步执行,业务处理的逻辑都在run()方法里,完全不用关心是同步还是异步执行,这种设计太绝了,妙啊。。。(PS:纯属个人猜测,没有求证过,O(∩_∩)O哈哈~)

命令执行的结果放到会议室(CommandContext)

活动结束后,会调用planContinueProcessOperation(),流程继续执行,进入下一个活动节点

6.  CompleteTaskCmd

回到最初的完成任务命令,我们指定任务执行调用的Runnable的run()方法,run()方法里面是调用命令的execute方法

所以,接下来看完成任务这个命令具体做了什么

7.  ActivityBehavior

要理解 Behavior 必须要和流程图联系起来,流程图上的一些元素比如 网关、用户任务、子流程、事件等等都有对应的行为,每种行为的处理方式都不同

ActivityBehavior 的实现类比较多,层级也比较深,不一一列举,以其中一个为例看看就行了

继续回到完成任务,刚才看到往agenda中放了一个 TriggerExecutionOperation,该操作触发等待状态并继续该流程,并离开该活动。

8.  回顾

Command:命令

ActivitiEngineAgendaFactory:用于创建ActivitiEngineAgenda

ActivitiEngineAgenda:议程,待议事项,用于循环执行Operation

AbstractOperation:事项/操作,它实现了Runnable接口

CommandContextFactory:用于创建CommandContext

CommandContext:每个命令执行线程都有自己的CommandContext,其内部有对Command和Agenda的引用

CommandExecutor:执行Command,从拦截器链的第一个拦截器开始执行

CommandInvoker:拦截器链上的最后一个拦截器,负责将命令封装成Operation,在Agenda中执行Operation的时候就会调用具体命令的execute方法

ActivityBehavior:代表活动的行为,这是真正底层的驱动流程流转的核心

Activiti 7 源码学习的更多相关文章

  1. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  2. jQuery源码学习感想

    还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码, ...

  3. MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)

    前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...

  4. MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)

    前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...

  5. MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)

    前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...

  6. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)

    前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...

  7. 我的angularjs源码学习之旅2——依赖注入

    依赖注入起源于实现控制反转的典型框架Spring框架,用来削减计算机程序的耦合问题.简单来说,在定义方法的时候,方法所依赖的对象就被隐性的注入到该方法中,在方法中可以直接使用,而不需要在执行该函数的时 ...

  8. ddms(基于 Express 的表单管理系统)源码学习

    ddms是基于express的一个表单管理系统,今天抽时间看了下它的代码,其实算不上源码学习,只是对它其中一些小的开发技巧做一些记录,希望以后在项目开发中能够实践下. 数据层封装 模块只对外暴露mod ...

  9. leveldb源码学习系列

    楼主从2014年7月份开始学习<>,由于书籍比较抽象,为了加深思考,同时开始了Google leveldb的源码学习,主要是想学习leveldb的设计思想和Google的C++编程规范.目 ...

随机推荐

  1. Educational Codeforces Round 128 (Rated for Div. 2) A-C+E

    Educational Codeforces Round 128 (Rated for Div. 2) A-C+E A 题目 https://codeforces.com/contest/1680/p ...

  2. NC20032 [HNOI2003]激光炸弹

    NC20032 [HNOI2003]激光炸弹 题目 题目描述 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标. 现在地图上有 \(n\) (\(N ≤ 10000\))个目标,用整数 ...

  3. cmd中常用的dos命令

    在电脑中除了我们常见的图形界面之外,图形页面的操作相信都会.那么还有在cmd执行的一些dos命令,可以简单记一下,方便日后复习所用 首先打开cmd窗口,windows+R,然后在对话框输入cmd,进入 ...

  4. 【python】自动更新pu口袋校园活动

    [python]自动更新pu口袋校园活动 脚本目标: 1. 自动爬取pu口袋校园活动,筛选出需要的活动,此处我的筛选条件是线上活动,因为可以不用去就可以白嫖学时 2. 自动发送邮件到QQ邮箱,每次只发 ...

  5. centos7 yum error yum doesn't have enough cached data

    1.vi /etc/resolv.conf,添加下面一行 nameserver 114.114.114.114 修改完成后service network restart进行重启,试一下yum upda ...

  6. 微信小程序使用echarts/数据刷新重新渲染/图层遮挡问题

    1.微信小程序使用echarts,首先下载echarts并导入小程序项目中,因小程序后期上线对文件大小有要求,所以建议进行定制下载导入可减少文件大小占比,也可以下载以前旧版本文件比较小的应付使用 下载 ...

  7. nginx概述及配置

    Nginx是什么? Nginx是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器.因它的稳定性.丰富的功能集.示例配置文件和低系统资源的消耗而闻名.20 ...

  8. 优雅哥学 Webpack - 01 - Webpack 5 快速体验

    程序员优雅哥简介:十年程序员,呆过央企外企私企,做过前端后端架构.分享vue.Java等前后端技术和架构 本文摘要:主要讲解 webpack 5 初体验.从webpack 5 初识到便写代码.优雅哥将 ...

  9. JavaScript进阶内容——DOM详解

    JavaScript进阶内容--DOM详解 当我们已经熟练掌握JavaScript的语法之后,我们就该进入更深层次的学习了 首先我们思考一下:JavaScript是用来做什么的? JavaScript ...

  10. 基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用

    在我们实际项目开发过程中,往往需要根据实际情况,对组件进行封装,以更简便的在界面代码中使用,在实际的前端应用中,适当的组件封装,可以减少很多重复的界面代码,并且能够非常简便的使用,本篇随笔介绍基于El ...