Activiti 7 源碼學習

来源:https://www.cnblogs.com/cjsblog/archive/2022/09/22/16718814.html
-Advertisement-
Play Games

1. 啟動分析 源碼版本是 7.1.0.M6 首先從 ProcessEngineAutoConfiguration 開始 ProcessEngineAutoConfiguration 是activiti-spring-boot-starter 7.1.0.M6自動配置的入口類,在這裡主要看 Spri ...


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中,因此TaskServicecommandExecutor的出現就不足為奇了

可以看到,完成任務的時候,直接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:代表活動的行為,這是真正底層的驅動流程流轉的核心


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在我看來並不是MVC的基礎上增加領域層,使用充血模型,解耦基礎服務,我的代碼就符合DDD了。 為什麼要使用DDD? DDD分為戰略部分跟戰術部分,相信大家都認同DDD的核心在戰略而非戰術。而戰略方面的核心我認為在業務建模,領域劃分、統一語言等都在為業務建模服務。 為什麼業務建模重要? ... ...
  • 目錄 一.OpenGL ES 圖像飽和度調節 1.原始圖片 2.效果演示 二.OpenGL ES 圖像飽和度調節源碼下載 三.猜你喜歡 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL ES 學習路線推薦 : OpenG ...
  • 多用戶即時通訊系統03 4.編碼實現02 4.4功能實現-私聊功能實現 4.4.1思路分析 客戶端 - 發送者: 用戶在控制台輸入信息,客戶端接收內容 將消息構建成Messgae對象,通過對應的socket發送給伺服器 伺服器: 可以讀取到客戶端(發送者)發送給某個用戶(接收者)的消息 從管理線程的 ...
  • Java基礎鞏固(二)——多線程 1.基本概念 程式是指令和數據的有序集合,其本身沒有任何運行的含義,是一個靜態的概念。 進程是執行程式的一次執行過程,它是一個動態的概念。是系統資源分配的單位。 一個進程可以包含若幹個線程,線程是cpu調度和執行的單位。 ==進程是資源分配的最小單位,線程是程式執行 ...
  • Java後端開發——美團(牛客) Java的基本數據類型,各自的位元組數 ​ 老生常談,不多說了. | 類型 | 位元組數 | | | | | byte | 1位元組 | | short | 2位元組 | | int | 4位元組 | | long | 8位元組 | | float | 4位元組 | | doub ...
  • 多用戶即時通訊系統03 4.編碼實現02 4.3功能實現-無異常退出系統 4.3.1思路分析 上述代碼運行時,在客戶端選擇退出系統的時候,可以發現程式並沒有停止運行,原因是: 退出時,程式將迴圈標誌loop設為false,退出了內層迴圈,而外層迴圈因為也用了loop來作為迴圈條件,外層迴圈也同樣退出 ...
  • 多用戶即時通訊系統03 4.編碼實現02 4.2功能實現-拉取線上用戶 4.2.1思路分析 客戶端想要知道線上用戶列表,就要向伺服器發送請求(Message),因為只有伺服器端保持著所有與客戶端相連接的socket和uid信息。 整個流程大致為:對Message的種類進行擴展,然後客戶端向伺服器發送 ...
  • 一、事務操作 模塊 from django.db import transaction 1 開啟事務:with transaction.atomic() from django.db import transaction class MyView(View): def post(self, requ ...
一周排行
    -Advertisement-
    Play Games
  • 一:背景 1.講故事 在分析的眾多dump中,經常會遇到各種奇葩的問題,僅通過dump這種快照形式還是有很多問題搞不定,而通過 perfview 這種粒度又太粗,很難找到問題之所在,真的很頭疼,比如本篇的 短命線程 問題,參考圖如下: 我們在 t2 時刻抓取的dump對查看 短命線程 毫無幫助,我根 ...
  • 在日常後端Api開發中,我們跟前端的溝通中,通常需要協商好入參的數據類型,和參數是通過什麼方式存在於請求中的,是表單(form)、請求體(body)、地址欄參數(query)、還是說通過請求頭(header)。 當協商好後,我們的介面又需要怎麼去接收這些數據呢?很多小伙伴可能上手就是直接寫一個實體, ...
  • 許多情況下我們需要用到攝像頭獲取圖像,進而處理圖像,這篇博文介紹利用pyqt5、OpenCV實現用電腦上連接的攝像頭拍照並保存照片。為了使用和後續開發方便,這裡利用pyqt5設計了個相機界面,後面將介紹如何實現,要點包括界面設計、邏輯實現及完整代碼。 ...
  • 思路分析 註冊頁面需要對用戶提交的數據進行校驗,並且需要對用戶輸入錯誤的地方進行提示! 所有我們需要使用forms組件搭建註冊頁面! 平時我們書寫form是組件的時候是在views.py裡面書寫的, 但是為了接耦合,我們需要將forms組件都單獨寫在一個地方,需要用的時候導入就行! 例如,在項目文件 ...
  • 思路分析 登錄頁面,我們還是採用ajax的方式提交用戶數據 唯一需要學習的是如何製作圖片驗證碼! 具體的登錄頁面效果圖如下: 如何製作圖片驗證碼 推導步驟1:在img標簽的src屬性里放上驗證碼的請求路徑 補充1.img的src屬性: 1.圖片路徑 2.url 3.圖片的二進位數據 補充2:字體樣式 ...
  • 哈嘍,兄弟們! 最近有許多小伙伴都在吐槽打工好難。 每天都是執行許多重覆的任務 例如閱讀新聞、發郵件、查看天氣、打開書簽、清理文件夾等等, 使用自動化腳本,就無需手動一次又一次地完成這些任務, 非常方便啊有木有?! 而在某種程度上,Python 就是自動化的代名詞。 今天就來和大家一起學習一下, 用 ...
  • 作者:IT王小二 博客:https://itwxe.com 前面小二介紹過使用Typora+PicGo+LskyPro打造舒適寫作環境,那時候需要使用水印功能,但是小二在升級LskyPro2.x版本發現有很多不如人意的東西,遂棄用LskyPro使用MinIO結合代碼實現自己需要的圖床功能,也適合以後 ...
  • OpenAI Gym是一款用於研發和比較強化學習演算法的工具包,本文主要介紹Gym模擬環境的功能和工具包的使用方法,並詳細介紹其中的經典控制問題中的倒立擺(CartPole-v0/1)問題。最後針對倒立擺問題如何建立控制模型並採用爬山演算法優化進行了介紹,並給出了相應的完整python代碼示例和解釋。要... ...
  • python爬蟲瀏覽器偽裝 #導入urllib.request模塊 import urllib.request #設置請求頭 headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, l ...
  • 前端代碼搭建 主要利用的是bootstrap3中js插件里的模態框版塊 <li><a href="" data-toggle="modal" data-target=".bs-example-modal-lg">修改密碼</a></li> <div class="modal fade bs-exam ...