jBPM4實(shí)現(xiàn)基本活動(上)
5.1. ActivityBehaviour
PVM庫沒有包含完整的流程結(jié)構(gòu)。 作為替代的是,活動的運(yùn)行時(shí)行為被委派給一個(gè)ActivityBehaviour。 換句話講,ActivityBehaviour是一個(gè)接口, 它用來在純java環(huán)境實(shí)現(xiàn)流程結(jié)構(gòu)的運(yùn)行時(shí)行為。
- public interface ActivityBehaviour extends Serializable {
- void execute(ActivityExecution execution) throws Exception;
- }
當(dāng)一個(gè)活動行為被調(diào)用時(shí),它就處于執(zhí)行傳播的全部控制中。 換句話說,一個(gè)活動行為可以決定下一步應(yīng)該執(zhí)行什么執(zhí)行。 比如,可以使用execution.take(Transition)獲得一個(gè)轉(zhuǎn)移, 或者使用execution.waitForSignal()進(jìn)入等待階段。 萬一活動行為沒有調(diào)用任何上述的執(zhí)行傳播方法, 執(zhí)行將 按默認(rèn)方式執(zhí)行。
5.2. ActivityBehaviour實(shí)例
我們會啟動一個(gè)非常原始的hello world例子。 一個(gè)Display活動會將一條信息打印到控制臺:
- public class Display implements ActivityBehaviour {
- String message;
- public Display(String message) {
- this.message = message;
- }
- public void execute(ActivityExecution execution) {
- System.out.println(message);
- }
- }
讓我們使用這個(gè)活動構(gòu)建我們第一個(gè)流程定義:
Display實(shí)例流程
圖 5.1. Display實(shí)例流程
TODO add ProcessBuilder example code
現(xiàn)在我們可以像下面這樣執(zhí)行流程:
Execution execution = processDefinition.startExecution();
startExecution的調(diào)用會在控制臺打印hello world:
hello
world
一個(gè)總是值得提醒的事情是活動可以使用屬性進(jìn)行配置。 在Display例子中,你可以看到message屬性在兩種使用方法中配置的不同。 通過配置屬性,我們可以寫出可復(fù)用的活動。 它們可以在以后每次使用在流程中都進(jìn)行不同的配置。 這是一個(gè)基本的部分, 將流程語言構(gòu)建在流程虛擬機(jī)之上。
其他需要解釋的部分是 這個(gè)活動實(shí)現(xiàn)沒有包含任何執(zhí)行傳播的功能。 當(dāng)一個(gè)新流程實(shí)例啟動時(shí), 執(zhí)行會定位到初始活動,那個(gè)活動會被執(zhí)行。 Display.execute方法用來決定默認(rèn)的執(zhí)行傳播。 具體的,這意味著活動自己 沒有調(diào)用任何執(zhí)行傳播的方法。 那種情況下,默認(rèn)的傳播會執(zhí)行。默認(rèn)傳播會選擇第一個(gè)轉(zhuǎn)移,如果這個(gè)轉(zhuǎn)移存在的話。 如果沒有,它會結(jié)束這個(gè)執(zhí)行。 這揭示了為什么a活動和b活動都被執(zhí)行, 而在b活動執(zhí)行完執(zhí)行會停止。
關(guān)于默認(rèn)流程行為的更多細(xì)節(jié)可以 在第 7.3 節(jié) “默認(rèn)執(zhí)行行為”找到。
5.3. ExternalActivityBehaviour
外部活動是負(fù)責(zé)流程執(zhí)行由外部轉(zhuǎn)移進(jìn)來的活動, 外部的意思是來自流程系統(tǒng)的外部。 這意味著這個(gè)執(zhí)行流程對于系統(tǒng)來說,這是一個(gè)等待狀態(tài)。 這個(gè)執(zhí)行會一直等待到外部觸發(fā)器調(diào)用。
為了處理外部觸發(fā)器,ExternalActivityBehaviour 為ActivityBehaviour添加了一個(gè)方法:
- public interface ExternalActivity extends Activity {
- void signal(Execution execution,
- String signal,
- Map
parameters) throws Exception;- }
就像普通的活動,當(dāng)一個(gè)執(zhí)行到達(dá)一個(gè)活動, 外部活動行為的execute方法會被調(diào)用。 在外部活動中,execute方法會傳遞另一個(gè)系統(tǒng)的響應(yīng), 然后通過調(diào)用execution.waitForSignal() 進(jìn)入等待狀態(tài)。 比如在execute方法中,響應(yīng)可能是由一個(gè)人傳入, 通過在任務(wù)管理系統(tǒng)中創(chuàng)建一個(gè)任務(wù)入口, 然后等待到這個(gè)人完成這個(gè)任務(wù)。
一旦活動行為已經(jīng)處于等待狀態(tài), 然后執(zhí)行會等待到調(diào)用signal方法。 執(zhí)行會委派signal給ExternalActivityBehaviour對象 分配給當(dāng)前的活動。
所以活動的signal方法 會在等待期間,在執(zhí)行獲得一個(gè)外部觸發(fā)器的時(shí)候調(diào)用。 signal方法中,響應(yīng)會傳遞給后面的流程執(zhí)行。 比如,當(dāng)一個(gè)人完成了一個(gè)任務(wù),任務(wù)管理系統(tǒng) 會在執(zhí)行中調(diào)用signal方法。
一個(gè)signal可選擇使用signal名字和一個(gè)參數(shù)map。 活動行為攔截signal和參數(shù)的最常用方式是 signal對應(yīng)選擇的外出轉(zhuǎn)移, 參數(shù)作為執(zhí)行中的變量。但那些只是例子, 它一直等到活動使用singal和它期望的參數(shù)。
5.4. ExternalActivity實(shí)例
這里是一個(gè)簡單等待狀態(tài)實(shí)現(xiàn)的第一個(gè)例子:
- public class WaitState implements ExternalActivity {
- public void execute(ActivityExecution execution) {
- execution.waitForSignal();
- }
- public void signal(ActivityExecution execution,
- String signalName,
- Map
parameters) { - execution.take(signalName);
- }
- }
execute方法調(diào)用execution.waitForSignal()。 execution.waitForSignal()的調(diào)用 會使流程執(zhí)行進(jìn)入等待狀態(tài), 直到一個(gè)外部觸發(fā)器出現(xiàn)。
signal方法使用signal參數(shù)對應(yīng)的轉(zhuǎn)移名稱 來選擇轉(zhuǎn)移。所以當(dāng)一個(gè)執(zhí)行獲得一個(gè)外部觸發(fā)器, signal名稱被攔截,作為外部轉(zhuǎn)移的名稱, 執(zhí)行會被傳播到那個(gè)轉(zhuǎn)移上。
這里是從a到b有一個(gè)轉(zhuǎn)移的相同的流程。 這時(shí)候,兩個(gè)活動的行為都是WaitState。
外部活動實(shí)例流程
圖 5.2. 外部活動實(shí)例流程
- ClientProcessDefinition processDefinition = ProcessFactory.build()
- .activity("a").initial().behaviour(new WaitState())
- .transition().to("b")
- .activity("b").behaviour(new WaitState())
- .done();
讓我們?yōu)榱鞒潭x啟動一個(gè)新流程實(shí)例:
ClientExecution execution = processDefinition.startProcessInstance();
啟動這個(gè)流程會執(zhí)行a中的WaitState活動。 WaitState.execute會調(diào)用 ActivityExecution.waitForSignal。 所以當(dāng)processDefinition.startProcessInstance()返回, 執(zhí)行會一直處在a活動。
assertEquals("a", execution.getActivityName());
然后我們提供了外部觸發(fā)器, 通過調(diào)用signal方法。
execution.signal();
execution.signal()會委派給當(dāng)前活動。 所以在這種情況下就是a活動里的 WaitState活動。WaitState.signal會調(diào)用 ActivityExecution.take(String transitionName)。 當(dāng)我們沒有提供一個(gè)signal名稱,第一個(gè)名字是null會被選中。 我們指定的a的唯一轉(zhuǎn)移沒有名字,所以會選中這個(gè)。 然后這個(gè)轉(zhuǎn)移指向b。 當(dāng)執(zhí)行到達(dá)b活動, b活動中的WaitState活動會被執(zhí)行。 就像我們上面看到的,執(zhí)行會在b一直等待, 這時(shí)signal會返回, 離開的執(zhí)行指向b活動。
assertEquals("b", execution.getActivityName());
【編輯推薦】