為了支持多次自動循環(huán)執(zhí)行,流程虛擬機 把執(zhí)行的傳播從尾部遞歸轉換成while循環(huán)。
7.2. 子流程
TODO: 子流程
7.3. 默認執(zhí)行行為
當一個Activity被用作活動行為, 它可以使用下面的方法從外部控制流程:
* waitForSignal()
* take(Transition)
* end(*)
* execute(Activity)
* createExecution(*)
當Activity實現(xiàn)用做活動行為, 沒有調用任何下面的流程傳播方法,然后 在活動執(zhí)行時,執(zhí)行會使用默認執(zhí)行行為。
默認執(zhí)行行為定義在下面:
* 如果當前活動有一個默認向外轉移,選擇它。
* 如果當前活動有一個父活動,回退到父活動。
* 否則,結束這個執(zhí)行。
流程語言可以重寫默認執(zhí)行行為, 通過重寫ExecutionImpl中的 proceed方法。
7.4. 功能活動
活動也可以用作事件監(jiān)聽器,被稱作功能活動。 自動活動的例子是發(fā)送郵件,執(zhí)行數(shù)據(jù)庫更新, 生成pdf,計算平均數(shù),等等。 所有這些都是自動活動,沒有改變執(zhí)行流向。 這里是這些活動如何實現(xiàn):
public class FunctionalActivity implements Activity, EventListener {
public void execute(ActivityExecution execution) {
perform(execution);
}
public void notify(EventListenerExecution execution) {
perform(execution);
}
void perform(OpenExecution execution) {
...do functional work...
}
}
perform方法獲得一個OpenExecution, 這是ActivityExecution和 EventListenerExecution的超類。 OpenExecution沒有提供任何特定目的的方法, 但是依舊是當前狀態(tài),流程定義可以通過變量檢驗, 這包含了環(huán)境信息 對應流程執(zhí)行。
這些方法其實都不能調用執(zhí)行傳播方法。 所以在perform方法完成后,執(zhí)行會 執(zhí)行默認的方式。
7.5. 執(zhí)行和線程
這一章解釋流程虛擬機如何通過客戶端的線程, 把一個執(zhí)行從一個等待狀態(tài)帶到另一個。
當一個客戶調用一個執(zhí)行的一個方法(比如signal方法)。 默認,流程虛擬機會使用線程執(zhí)行流程 直到它到達一個等待狀態(tài)。一旦下一個等待狀態(tài)到達, 這個方法會返回,客戶端的線程就會返回。 這是流程虛擬機操作的默認方式。 兩個更多的異步執(zhí)行可以補充默認行為: 異步繼續(xù) 和異步命令服務。
下一個流程會展示基本理論。 它有三個等待狀態(tài)和四個自動活動。
有很多順序自動活動的流程。

圖 7.1. 有很多順序自動活動的流程。
這里是如何構建流程:
ClientProcessDefinition processDefinition = ProcessFactory.build("automatic")
.activity("wait 1").initial().behaviour(new WaitState())
.transition().to("automatic 1")
.activity("automatic 1").behaviour(new Display("one"))
.transition().to("wait 2")
.activity("wait 2").behaviour(new WaitState())
.transition().to("automatic 2")
.activity("automatic 2").behaviour(new Display("two"))
.transition().to("automatic 3")
.activity("automatic 3").behaviour(new Display("three"))
.transition().to("automatic 4")
.activity("automatic 4").behaviour(new Display("four"))
.transition().to("wait 3")
.activity("wait 3").behaviour(new WaitState())
.done();
讓我們和你一起順著流程的執(zhí)行一起走。
ClientExecution execution = processDefinition.startProcessInstance();
啟動一個新執(zhí)行意味著初始活動被執(zhí)行。 所以如果一個自動活動是初始活動,這意味著第一個未命名的向外轉移會被立刻選擇。 這些都發(fā)生在startProcessInstance調用的內部。
然而在這種情況下,初始活動是一個等待狀態(tài)。 所以startProcessInstance方法會立刻返回, 執(zhí)行會定位到初始活動'wait 1'。
一個新執(zhí)行會被定為到'wait 1'。

圖 7.2. 一個新執(zhí)行會被定為到'wait 1'。
然后一個外部觸發(fā)器會執(zhí)行signal方法。
execution.signal();
像上面解釋的介紹WaitState, signal會導致選擇默認的轉移。 轉移會把執(zhí)行移動到automatic 1活動,并執(zhí)行它。 automatic 1中的Display活動的execute方法, 向控制臺打印一行,它不會 調用execution.waitForSignal()。 因此,執(zhí)行會通過選擇automatic 1外部的默認轉移進行執(zhí)行。 在這種狀態(tài),signal方法一直阻塞著。另一個需要考慮的方式是執(zhí)行方法, 像signal會使用客戶端的線程 來攔截流程定義,直到到達一個等待狀態(tài)。
然后執(zhí)行到達wait 2, 執(zhí)行WaitState活動。那個方法會調用 execution.waitForSignal(),這會導致signal方法返回。 線程會返回到調用signal方法 的客戶端。
所以,當signal方法返回時,執(zhí)行定義到wait 2。
一個signal會把執(zhí)行從'initial'帶到'wait 2'。

圖 7.3. 一個signal會把執(zhí)行從'initial'帶到'wait 2'。
然后執(zhí)行會等待一個外部觸發(fā)器, 像是一個對象(更準確的是一個對象圖)在內存中, 直到下一個外部觸發(fā)器執(zhí)行signal方法。
execution.signal();
第二個調用的signal會直接讓執(zhí)行進入wait 3, 在它返回之前。
第二個signal讓執(zhí)行進入'wait 3'。

圖 7.4. 第二個signal讓執(zhí)行進入'wait 3'。
使用這個范例的好處是相同的流程定義可以在 客戶執(zhí)行模式中執(zhí)行 (在內存內不使用持久化),就像在持久化執(zhí)行模式, 依賴應用和環(huán)境。
當在持久化模式下執(zhí)行一個流程,你如何綁定 流程執(zhí)行到數(shù)據(jù)庫的事務上。
持久化模式下的事務超時

圖 7.5. 持久化模式下的事務超時
在大多情況下,計算工作是流程需要完成的一部分, 在外部觸發(fā)器(紅色部分)之后的部分,其實很少。 一般來說,處理流程執(zhí)行和處理UI傳遞過來的請求 的事務不會超過一秒。 而業(yè)務流程中的等待狀態(tài)可能超過幾小時,幾天甚至幾年。 當?shù)却隣顟B(tài)啟動后,線索就變得很清晰, 在等待狀態(tài)啟動之前,只有計算工作的完成包含在事務中。
考慮一下這種方式: "當?shù)竭_審批時,所有的自動流程需要做的是什么, 在流程系統(tǒng)需要等待另一個外部觸發(fā)器之前?"。 除非pdf需要被創(chuàng)建,或大郵件需要被發(fā)送, 大部分時候,它消耗的時間都是可以忽略的。 這就是為什么在默認的持久化執(zhí)行模式下, 流程工作在客戶端線程下執(zhí)行。
這個原因也保證著流程同步路徑的情況。 當一個執(zhí)行的單獨路徑切分成流程同步路徑, 流程花在計算上的時間是可忽略的。 所以為什么分支或切分活動實現(xiàn)是有意義的, 目標持久化模式產生的同步路徑在同一個線程中按順序執(zhí)行。 基本上它們都只是在同一個事務中的計算工作。 因為分支或切分知道每個執(zhí)行的同步路徑會返回,所以這只能被完成, 當出現(xiàn)一個等待狀態(tài)的時候。
因為這里有一個困難的概念需要掌握,我會再次使用其他詞語來解釋它。 從頭再看一次在持久化執(zhí)行模式下被流程執(zhí)行創(chuàng)建出來的它。 如果在一個事務中,一個執(zhí)行被給與一個外部觸發(fā)器, 那導致執(zhí)行切分成多個執(zhí)行的同步路徑。 然后執(zhí)行在計算上的部分也可以忽略。 生成SQL的部分也可以忽略。 因為所有在同步分支上完成的功能,必須在同一個事務中完成, 這里一般沒有指針在分支或切分實現(xiàn), 在多個線程中產生執(zhí)行的同步路徑。
為了創(chuàng)建可執(zhí)行流程,開發(fā)者需要確切知道什么是自動活動, 什么是等待狀態(tài),哪些線程會被分配給流程執(zhí)行。 對于畫業(yè)務流程的業(yè)務分析人員,事件就很簡單了。 對于他們畫的活動,他們通常只要知道這是一個人或是一個系統(tǒng)響應。 但是他們通常不知道如何轉換線程和事務。
所以對于開發(fā)者,第一個任務是分析什么是流程控制的線程中需要執(zhí)行的, 什么是外部的。 查找外部觸發(fā)器是尋找一個流程中的等待狀態(tài)的很好的開始, 就像動詞和名詞可以在構建UML類圖中的元素的規(guī)則。