Activiti7源码学习

  1. 启动分析

源码版本是 7.1.0.M6

首先从 ProcessEngineAutoConfiguration 开始

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

Activiti7源码学习

Activiti7源码学习

主要是配置了自动部署

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

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

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

Activiti7源码学习

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

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

initAgendaFactory()

Activiti7源码学习
Activiti7源码学习

initCommandContextFactory()

Activiti7源码学习
Activiti7源码学习

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

initCommandExecutors()

Activiti7源码学习
Activiti7源码学习

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

Activiti7源码学习

initServices()

Activiti7源码学习

initBehaviorFactory()

Activiti7源码学习

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

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

Activiti7源码学习
  1. CommandContextInterceptor

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

Activiti7源码学习

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

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

Activiti7源码学习

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

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

Activiti7源码学习

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

  1. Command

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

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

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

Activiti7源码学习

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

Activiti7源码学习

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

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

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

Activiti7源码学习

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

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

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

Activiti7源码学习

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

  1. CommandInvoker

Activiti7源码学习

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

Activiti7源码学习

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

  1. Agenda

Activiti7源码学习

Activiti7源码学习

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

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

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

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

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

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

Activiti7源码学习

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

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

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

  1. CompleteTaskCmd

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

Activiti7源码学习

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

Activiti7源码学习
Activiti7源码学习
Activiti7源码学习
  1. ActivityBehavior

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

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

Activiti7源码学习

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

Activiti7源码学习
Activiti7源码学习
  1. 回顾

Command:命令

ActivitiEngineAgendaFactory:用于创建ActivitiEngineAgenda

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

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

CommandContextFactory:用于创建CommandContext

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

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

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

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

Activiti7源码学习

Original: https://www.cnblogs.com/cjsblog/p/16718814.html
Author: 废物大师兄
Title: Activiti7源码学习

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/712777/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 继承与初始化

    了解包括继承在内的初始化全过程: 执行结果: 程序运行时,先试图访问Beetle.main()(一个static方法),访问Beetle类的静态方法将会使Beetle类加载,即加载…

    技术杂谈 2023年7月23日
    060
  • Python对字符数据进行清洗

    import re mystr = "hahaAAA哈哈綂123./!#鱫愛" str1 = ”.join(re.findall(‘[\u4e00-\u9fa…

    技术杂谈 2023年7月24日
    079
  • 字符串

    20、【剑指Offer学习】【面试题20:表示数值的字符串】 38、【剑指Offer学习】【面试题38:字符串的排列】 46、【剑指Offer学习】【面试题46:把数字翻译成字符串…

    技术杂谈 2023年6月22日
    070
  • 子串次数——类似KMP

    老规矩 先来看问题 字符串a 在A中出现了多少次 求次数 。 当然有很多种算法 最简单的 一个一个找呗 不过这种太麻烦 我们不讲这种 我在写这个算法的时候 用到了KMP算法的部分内…

    技术杂谈 2023年7月23日
    085
  • java设计模式:观察者模式

    参考博客:Java观察者模式(Observer)SpringBoot事件监听机制及观察者模式/发布订阅模式 1.使用场景 聊天室程序的创建。服务器创建好后,A,B,C三个客户端连上…

    技术杂谈 2023年7月24日
    084
  • 文件的压缩与打包

    文件的压缩与打包 常用文件拓展名 *.tar.gz tar程序打包的文件,并且经过gzip的压缩 *.tar.bz2 tar程序打包的文件,并且经过bzip2的压缩 tar 命令,…

    技术杂谈 2023年7月11日
    072
  • 蓝桥杯——校内模拟题目分析

    蓝桥杯——校 内模拟题目分析 (顺序有可能会有点乱,不要信上面填的答案,看解析,后面附有答案) 1 这道题就不用多说了吧,计算机的单位之间进制为2 的10 次方 所以答案为: 15…

    技术杂谈 2023年7月23日
    078
  • 利用freemarker导出页面格式复杂的excel

    刚开始大家可能会利用poi生成简单的excel,但是遇到需要生成复杂的excel,poi导出excel就比较困难,这时候可以利用freemarker来渲染实现实现生成复杂的exce…

    技术杂谈 2023年6月1日
    0116
  • quartz获取当前执行了几次

    public void execute(JobExecutionContext context) throws JobExecutionException { System.out…

    技术杂谈 2023年5月31日
    087
  • WordPress网站中添加百度统计代码

    百度统计是流量分析平台,帮助收集网站访问数据,提供流量趋势、来源分析、转化跟踪、页面热力图、访问流等多种统计分析服务,同时与百度搜索、百度推广、云服务无缝结合,为网站的精细化运营决…

    技术杂谈 2023年7月11日
    099
  • idea导入项目MAVEN报错,jdk与jms问题,以及@override报错

    一: Plugins报错: compiler Failed to execute goal org.apache.maven.plugins:maven-compiler-plug…

    技术杂谈 2023年7月24日
    099
  • UnixBench算分介绍【转】

    关于如何用UnixBench,介绍文章很多,这里就不展开了。这里重点描述下它是如何算分的。 碰到很多客户,装好后,直接./Run,就把结果跑出来了,然后还只取最后一个分值,比谁高谁…

    技术杂谈 2023年5月31日
    0111
  • djangomodelform

    python view.py class UserModelForm(forms.ModelForm): class Meta: model = models.UserInfo f…

    技术杂谈 2023年7月24日
    092
  • Mixin Messenger 源码解读 1 — — WCDB Swift

    Mixin Messenger 早期采用 FMDB 后来切换至 WCDB 沿用至今,一直比较可靠稳定,这里分享一下使用心得和功能扩展。 Mixin Messenger 是一个开源的…

    技术杂谈 2023年5月31日
    095
  • Badger简单使用

    badger 是 dgraph 开源的 LSMTree 的 KV 引擎,它相比 leveldb 有 KV 分离、事务、并发合并等增强,是 go 生态中比较生产级的存储引擎了。 要开…

    技术杂谈 2023年7月24日
    064
  • 每日一考-9.15

    wait和sleep的区别 简说:wait释放🔒,sleep不释放🔒 例子:买票过程中,当程序进行上锁后 sleep控制下的线程,买票是一一完成,当程序休眠后,sleep不会释放🔒…

    技术杂谈 2023年7月11日
    071
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球