任務是流程中最重要的組成部分。Flowable提供了多種任務型別,以滿足實際需求。
常用任務型別有:
-
使用者任務
-
Java Service任務
-
指令碼任務
-
業務規則任務
-
執行監聽器
-
任務監聽器
-
多例項
整合擴充套件的任務型別有:
-
手動任務
-
Java接收任務
-
Shell任務
-
補償處理器
-
Web Service任務
-
郵件任務
-
Http任務
-
Camel任務
-
Mule任務
任務的圖形都是以一個圓角矩形為基礎,在左上角新增具體型別的圖示。
一、常用的任務型別
1.1 使用者任務
1.1.1 描述
“使用者任務(user task)”指需要人工執行的任務。當流程執行到達使用者任務時,流程例項會停止等待,直到使用者觸發完成任務動作。
1.1.2 圖示
使用者任務用左上角有一個小使用者圖示的標準任務(圓角矩形)表示。
1.1.3 XML表示
使用者任務在XML中如下定義。其中id是必須屬性,name是可選屬性。
<userTask id="theTask" name="重要任務" />
1.1.4 到期日期
每個任務都可以設定到期日期(due date)。
可以指定固定時間或相對時間,比如,當dueDate為“PT30M”時,表示到達任務30分鐘後到期。
到期日期必須符合java.util.Date或java.util.String(ISO8601格式)。
實際應用,我們指定為變數值。
<userTask id="theTask" name="Important task" flowable:dueDate="${dateVariable}"/>
任務的到期日期可以使用TaskService,或者在TaskListener中使用傳遞的DelegateTask修改。
1.1.5 任務指派
- 指派確定的辦理人
<userTask id="theTask" name="重要任務" flowable:assignee="jinyangjie"/>
- 指派潛在辦理人
<userTask id="theTask" name="重要任務" flowable:candidateUsers="jinyangjie, zhangsan" />
- 指派潛在辦理組
<userTask id="theTask" name="重要任務" flowable:candidateGroups="leader, manager" />
更多工指派的內容,已在“使用者和組”的篇章中介紹,這裡不再贅述。
1.2 Java Service任務
1.2.1 描述
Java Service任務(Java service task)用於呼叫Java類。Java Service不屬於BPMN2.0規範,而是Flowable的自定義擴充套件。
1.2.2 圖示
服務任務用左上角有一個小齒輪圖示的圓角矩形表示。
1.2.3 XML表示
有三種方法宣告如何呼叫Java邏輯,下面分別介紹:
- 呼叫固定的類
使用flowable:class屬性提供全限定類名(fully qualified classname),指定流程執行時呼叫的類,該類必須實現JavaDelegate或ActivityBehavior介面。
<serviceTask id="javaService" flowable:class="com.example.service.MyJavaDelegate" />
- 呼叫動態類
使用flowable:delegateExpression屬性提供委託物件(delegation object)的表示式。該功能和flowable:class類似,同樣需要實現JavaDelegate或ActivityBehavior介面,只不過這裡不是指定一個具體的實現類,而是查詢指定名稱的Bean物件。
<serviceTask id="javaService" flowable:delegateExpression="${myDelegateExpressionBean}" />
myDelegateExpressionBean
是一個實現了JavaDelegate
介面的bean,定義在Spring容器中。
- 呼叫類的指定方法或屬性值
使用flowable:expression屬性指定類的方法或屬性值。同樣的,該類需要實現JavaDelegate或ActivityBehavior介面。
<serviceTask id="javaService" flowable:expression="#{printer.printMessage()}" />
將在名為printer
的物件上呼叫printMessage
方法(不帶引數)。當然也可以為表示式中使用的方法傳遞變數。
屬性值示例:
<serviceTask id="javaService" flowable:expression="#{printer.ready}" />
會呼叫名為printer
的bean的ready
引數的getter方法,getReady
(不帶引數)。該值會被解析為執行的流程變數。
1.2.4 具體實現例項
下面是一個Java類的示例,用於將流程變數String改為大寫。這個類通過實現org.flowable.engine.delegate.JavaDelegate介面,可以在流程執行中被呼叫。
同時,需要重寫execute(DelegateExecution)方法實現業務邏輯。這個方法就是引擎將呼叫的方法。另外,通過該方法中的DelegateExecution引數可以訪問流程例項的各種資訊。
public class ToUppercase implements JavaDelegate {
public void execute(DelegateExecution execution) {
String var = (String) execution.getVariable("input");
var = var.toUpperCase();
execution.setVariable("input", var);
}
}
如果實現org.flowable.engine.impl.delegate.ActivityBehavior介面,可以訪問更強大的引擎功能,例如,可以影響流程的控制流程。但注意這並不是好的實踐,需要避免這麼使用。
1.2.5 任務的返回值
服務執行的返回值(僅對使用表示式的服務任務),可以通過為服務任務定義的'flowable:resultVariable'屬性設定為流程變數。可以是已經存在的,或者新的流程變數。 如果指定為已存在的流程變數,則流程變數的值會被服務執行的返回值覆蓋。 如果不指定結果變數名,則服務任務的返回值將被忽略。
<serviceTask id="aMethodExpressionServiceTask"
flowable:expression="#{myService.doSomething()}"
flowable:resultVariable="myVar" />
在上例中,服務執行的結果(呼叫'doSomething()'方法的返回值),在服務執行完成後,會設定為名為'myVar'的流程變數。
1.2.6 異常處理
當執行自定義邏輯時,通常需要捕獲並在流程中處理特定的業務異常。Flowable提供了多種方式。
1.2.6.1 丟擲BPMN錯誤
可以在服務任務或指令碼任務的使用者程式碼中丟擲BPMN錯誤。可以在Java委託、指令碼、表示式與委託表示式中,丟擲特殊的FlowableException:BpmnError。引擎會捕獲這個異常,並將其轉發至合適的錯誤處理器,如錯誤邊界事件或錯誤事件子流程。
public class ThrowBpmnErrorDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception {
try {
executeBusinessLogic();
} catch (BusinessException e) {
throw new BpmnError("BusinessExceptionOccurred");
}
}
}
建構函式的引數是錯誤程式碼。錯誤程式碼決定了處理這個錯誤的錯誤處理器。
這個機制只應該用於業務錯誤,需要通過流程中定義的錯誤邊界事件或錯誤事件子流程處理。技術錯誤應該通過其他異常型別表現,並且通常不在流程內部處理。
1.2.6.2 異常對映
可以使用mapException
擴充套件,直接將Java異常對映至業務異常(錯誤)。單對映是最簡單的形式:
<serviceTask id="servicetask1" flowable:class="...">
<extensionElements>
<flowable:mapException
errorCode="myErrorCode1">com.example.SomeException</flowable:mapException>
</extensionElements>
</serviceTask>
在上面的程式碼中,如果服務任務丟擲org.flowable.SomeException
的例項,引擎會捕獲該異常,並將其轉換為帶有給定errorCode的BPMN錯誤。然後就可以像普通BPMN錯誤完全一樣地處理。其他的異常沒有對映,仍將丟擲至API呼叫處。
也可以在單行中使用includeChildExceptions
屬性,對映特定異常的所有子異常。
<serviceTask id="servicetask1" flowable:class="...">
<extensionElements>
<flowable:mapException errorCode="myErrorCode1"
includeChildExceptions="true">com.example.SomeException</flowable:mapException>
</extensionElements>
</serviceTask>
上面的程式碼中,Flowable會將SomeException
的任何直接或間接的子類,轉換為帶有指定錯誤程式碼的BPMN錯誤。 當未指定includeChildExceptions
時,視為“false”。
1.2.6.3 預設對映
預設對映最常用。預設對映是一個不指定類的對映,可以匹配任何Java異常:
<serviceTask id="servicetask1" flowable:class="...">
<extensionElements>
<flowable:mapException errorCode="myErrorCode1"/>
</extensionElements>
</serviceTask>
除了預設對映,會按照從上至下的順序檢查對映,使用第一個匹配的對映。只在所有對映都不能成功匹配時使用預設對映。 只有第一個不指定類的對映會作為預設對映。預設對映忽略includeChildExceptions
。
1.2.6.4 異常順序流
還有種推薦用法,在發生異常時,將流程執行路由至另一條路徑。下面是一個例子。
<serviceTask id="servicetask1" flowable:class="com.example.ThrowsExceptionBehavior">
</serviceTask>
<sequenceFlow id="no-exception" sourceRef="javaService" targetRef="theEnd" />
<sequenceFlow id="exception" sourceRef="javaService" targetRef="fixException" />
服務任務有兩條出口順序流,命名為exception
與no-exception
。在發生異常時,使用順序流ID控制流程流向:
public class ThrowsExceptionBehavior implements ActivityBehavior {
public void execute(DelegateExecution execution) {
String var = (String) execution.getVariable("var");
String sequenceFlowToTake = null;
try {
executeLogic(var);
sequenceFlowToTake = "no-exception";
} catch (Exception e) {
sequenceFlowToTake = "exception";
}
DelegateHelper.leaveDelegate(execution, sequenceFlowToTake);
}
}
1.3 指令碼任務
1.3.1 描述
指令碼任務(script task)是自動執行的活動。當流程執行到達指令碼任務時,會執行相應的指令碼。
1.3.2 圖示
指令碼任務用左上角有一個小“指令碼”圖示的標準BPMN 2.0任務(圓角矩形)表示。
1.3.3 XML表示
指令碼任務使用script與scriptFormat元素定義。
<scriptTask id="theScriptTask" scriptFormat="groovy">
<script>
sum = 0
for ( i in inputArray ) {
sum += i
}
</script>
</scriptTask>
預設情況下,JavaScript包含在每一個JDK中,因此不需要新增任何JAR檔案。如果想使用其它指令碼引擎,則需要在classpath中新增相應的jar,並使用適當的名字。例如,Flowable單元測試經常使用Groovy。Groovy指令碼引擎與groovy-all JAR捆綁在一起。新增如下依賴:
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.x.x<version>
</dependency>
1.3.4 指令碼中的變數
到達指令碼引擎的執行中,所有的流程變數都可以在指令碼中使用。在這個例子裡,指令碼變數'inputArray'實際上就是一個流程變數(一個integer的陣列)。
<script>
sum = 0
for ( i in inputArray ) {
sum += i
}
</script>
在指令碼中設定變數的例子:
<script>
def scriptVar = "test123"
execution.setVariable("myVar", scriptVar)
</script>
注意:下列名字是保留字,不能用於變數名:out,out:print,lang:import,context,elcontext。
1.3.5 指令碼任務的結果
指令碼任務的返回值,可以通過為指令碼任務定義的'flowable:resultVariable'屬性設定為流程變數。可以是已經存在的,或者新的流程變數。如果指定為已存在的流程變數,則流程變數的值會被指令碼執行的結果值覆蓋。如果不指定結果變數名,則指令碼結果值將被忽略。
<scriptTask id="theScriptTask" scriptFormat="juel" flowable:resultVariable="myVar">
<script>#{echo}</script>
</scriptTask>
在上面的例子中,指令碼執行的結果(解析表示式'#{echo}'的值),將在指令碼完成後,設定為名為'myVar'的流程變數。
1.4 業務規則任務
1.4.1 描述
在企業應用中,推薦做法是使用可維護的規則庫來管理複雜多變的業務規則,將業務程式碼和規則分開維護,一旦規則有變動,只需修改預設規則即可,而不會影響到業務程式碼。
業務規則任務可以根據流程變數的值處理預設的業務規則。Flowable支援目前最流行的規則引擎——Drools。只需把含有業務規則任務的流程檔案和規則引擎檔案“.drl”一同打包部署到系統中,同時新增Drools的jar包,即可實現Flowable驅動規則引擎。
1.4.2 圖示
業務規則任務顯示為帶有表格圖示的圓角矩形。
1.4.3 XML表示
要執行業務規則,需要定義輸入與結果變數。輸入變數可以用流程變數的列表定義,使用逗號分隔。輸出變數只能有一個變數名,如果沒有指定結果變數名,預設為org.flowable.engine.rules.OUTPUT。
<process id="simpleBusinessRuleProcess">
<startEvent id="theStart" />
<sequenceFlow sourceRef="theStart" targetRef="businessRuleTask" />
<businessRuleTask id="businessRuleTask" flowable:ruleVariablesInput="${order}"
flowable:resultVariable="rulesOutput" />
<sequenceFlow sourceRef="businessRuleTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
也可以將業務規則任務配置為只執行部署的.drl檔案中的一組規則。要做到這一點,需要指定規則名字的列表,用逗號分隔。
<businessRuleTask id="businessRuleTask" flowable:ruleVariablesInput="${order}"
flowable:rules="rule1, rule2" />
這樣只會執行rule1與rule2。
也可以定義需要從執行中排除的規則列表。
<businessRuleTask id="businessRuleTask" flowable:ruleVariablesInput="${order}"
flowable:rules="rule1, rule2" exclude="true" />
這個例子中,除了rule1與rule2之外,其它所有與流程定義一起部署的規則都會被執行。
注意:整合Drools的業務規則任務,是企業應用中的重要內容,需要重點掌握。
1.5 執行監聽器
1.5.1 描述
執行監聽器(execution listener)可以在流程執行中發生特定的事件時,執行外部Java程式碼或計算表示式。可以被捕獲的事件有:
- 流程例項的啟動和結束。
- 流程執行轉移。
- 活動的啟動和結束。
- 閘道器的啟動和結束。
- 中間事件的啟動和結束。
- 啟動事件的結束,和結束事件的啟動。
1.5.2 XML表示
下面的流程定義包含了三個執行監聽器:
<process id="executionListenersProcess">
<extensionElements>
<flowable:executionListener
class="org.flowable.examples.bpmn.executionlistener.ExampleExecutionListenerOne"
event="start" />
</extensionElements>
<startEvent id="theStart" />
<sequenceFlow sourceRef="theStart" targetRef="firstTask" />
<userTask id="firstTask" />
<sequenceFlow sourceRef="firstTask" targetRef="secondTask">
<extensionElements>
<flowable:executionListener
class="org.flowable.examples.bpmn.executionListener.ExampleExecutionListenerTwo" />
</extensionElements>
</sequenceFlow>
<userTask id="secondTask" >
<extensionElements>
<flowable:executionListener
expression="${myPojo.myMethod(execution.event)}"
event="end" />
</extensionElements>
</userTask>
<sequenceFlow sourceRef="secondTask" targetRef="thirdTask" />
<userTask id="thirdTask" />
<sequenceFlow sourceRef="thirdTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
第一個執行監聽器將在流程啟動時收到通知。這個監聽器是一個外部Java類(ExampleExecutionListenerOne
),並且需要實現org.flowable.engine.delegate.ExecutionListener
介面。當該事件發生時(這裡是start
事件),會呼叫notify(ExecutionListenerExecution execution)
方法。
public class ExampleExecutionListenerOne implements ExecutionListener {
public void notify(ExecutionListenerExecution execution) throws Exception {
execution.setVariable("variableSetInExecutionListener", "firstValue");
execution.setVariable("eventReceived", execution.getEventName());
}
}
也可以使用實現了org.flowable.engine.delegate.JavaDelegate
介面的委託類。這些委託類也可以用於其他的結構,如服務任務的委託。
第二個執行監聽器在流程執行轉移時被呼叫。請注意listener
元素並未定義event
,因為在轉移上只會觸發take
事件。當監聽器定義在轉移上時,event
屬性的值將被忽略。
最後一個執行監聽器在secondTask
活動結束時被呼叫。監聽器宣告中沒有使用class
,而是定義了expression
。這個表示式將在事件觸發時計算/呼叫。
<flowable:executionListener expression="${myPojo.myMethod(execution.eventName)}" event="end" />
與其他表示式一樣,可以使用與解析execution變數。
1.5.3 執行監聽器上的欄位注入
使用通過class
屬性配置的執行監聽器時,可以使用欄位注入。
下面的程式碼片段展示了一個簡單的示例流程,帶有一個使用了欄位注入的執行監聽器。
<process id="executionListenersProcess">
<extensionElements>
<flowable:executionListener
class="org.flowable.examples.bpmn.executionListener.ExampleFieldInjectedExecutionListener"
event="start">
<flowable:field name="fixedValue" stringValue="Yes, I am " />
<flowable:field name="dynamicValue" expression="${myVar}" />
</flowable:executionListener>
</extensionElements>
<startEvent id="theStart" />
<sequenceFlow sourceRef="theStart" targetRef="firstTask" />
<userTask id="firstTask" />
<sequenceFlow sourceRef="firstTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
ExampleFieldInjectedExecutionListener
類將連線兩個欄位(一個是固定值-fixedValue,另一個是動態值-dynamicValue),並將其儲存在'var
'流程變數中。
@Deployment(resources = {
"org/flowable/examples/bpmn/executionListener/ExecutionListenersFieldInjectionProcess.bpmn20.xml"})
public void testExecutionListenerFieldInjection() {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("myVar", "listening!");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
"executionListenersProcess", variables);
Object varSetByListener = runtimeService.getVariable(processInstance.getId(), "var");
assertNotNull(varSetByListener);
assertTrue(varSetByListener instanceof String);
// 結果為固定注入欄位及注入表示式的連線
assertEquals("Yes, I am listening!", varSetByListener);
}
1.6 任務監聽器
1.6.1 描述
任務監聽器(task listener)用於在特定的任務相關事件發生時,執行自定義的Java邏輯或表示式。
1.6.2 XML表示
任務監聽器只能在流程定義中作為使用者任務的子元素。請注意,任務監聽器是一個Flowable自定義結構,因此也需要作為BPMN 2.0 extensionElements,放在flowable名稱空間下。
<userTask id="myTask" >
<extensionElements>
<flowable:taskListener event="create" class="com.example.MyTaskCreateListener" />
</extensionElements>
</userTask>
1.6.3 任務監聽器屬性:
1.6.3.1 event
觸發任務監聽器的任務事件型別,必填項。可用的事件有:
- create(建立):當任務已經建立,並且所有任務引數都已經設定時觸發。
- assignment(指派):當任務已經指派給某人時觸發。請注意:當流程執行到達使用者任務時,在觸發create事件之前,會首先觸發assignment事件。這順序看起來不太自然,但是有實際原因的:當收到create事件時,我們通常希望能看到任務的所有引數,包括辦理人。
- complete(完成):當任務已經完成,從執行時資料中刪除前觸發。
- delete(刪除):在任務即將被刪除前觸發。請注意任務由completeTask正常完成時也會觸發。
1.6.3.2 class
需要呼叫的委託類。這個類必須實現org.flowable.engine.delegate.TaskListener
介面。
public class MyTaskCreateListener implements TaskListener {
public void notify(DelegateTask delegateTask) {
// 這裡是要實現的業務邏輯
}
}
也可以使用欄位注入,為委託類傳遞流程變數或執行。請注意委託類的例項在流程部署時建立(與Flowable中其它的委託類一樣),這意味著該例項會在所有流程例項執行中共享。
1.6.3.3 expression
指定在事件發生時要執行的表示式(不能與class屬性一起使用)。可以為被呼叫的物件傳遞DelegateTask
物件與事件名(使用task.eventName
)作為引數。
<flowable:taskListener event="create" expression="${myObject.callMethod(task, task.eventName)}" />
1.6.3.4 delegateExpression
指定一個能夠解析為TaskListener
介面實現類的物件的表示式。
<flowable:taskListener event="create" delegateExpression="${myTaskListenerBean}" />
1.7 多例項
1.7.1 描述
多例項活動(multi-instance activity)是在業務流程中,為特定步驟定義重複的方式。在程式設計概念中,多例項類似for each結構:可以為給定集合中的每一條目,順序或並行地,執行特定步驟,甚至是整個子流程。
閘道器和事件不能設定為多例項。
按照BPMN2.0規範的要求,用於為每個例項建立執行的父執行,會提供下列變數:
- nrOfInstances:例項總數。
- nrOfActiveInstances:當前活動的(即未完成的)例項數量。對於順序多例項,這個值總為1。
- nrOfCompletedInstances:已完成的例項數量。
可以呼叫execution.getVariable(x)
方法獲取這些值。
另外,每個被建立的執行,都有區域性變數(對其他執行不可見,也不儲存在流程例項級別):
- loopCounter:給定例項在for-each迴圈中的index。
1.7.2 圖示
如果一個活動是多例項,將通過在該活動底部的三條短線表示。三條豎線代表例項會並行執行,而三條橫線代表順序執行。
1.7.3 XML表示
要將活動變成多例項,該活動的XML元素必須有multiInstanceLoopCharacteristics
子元素
<multiInstanceLoopCharacteristics isSequential="false|true">
...
</multiInstanceLoopCharacteristics>
isSequential屬性代表了活動的例項為順序還是並行執行。
有4種不同方法可以配置數量。
1.7.3.1 指定數字
通過loopCardinality子元素,直接指定數字:
<multiInstanceLoopCharacteristics isSequential="false|true">
<loopCardinality>5</loopCardinality>
</multiInstanceLoopCharacteristics>
1.7.3.2 表示式
使用解析為正整數的表示式:
<multiInstanceLoopCharacteristics isSequential="false|true">
<loopCardinality>${nrOfOrders-nrOfCancellations}</loopCardinality>
</multiInstanceLoopCharacteristics>
1.7.3.3 指定集合
另一個定義例項數量的方法,是使用loopDataInputRef
子元素,指定一個集合型流程變數的名字。對集合中的每一項,都會建立一個例項。可以使用inputDataItem
子元素,將該項設定給該例項的區域性變數。在下面的XML示例中展示:
<userTask id="miTasks" name="My Task ${loopCounter}" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false">
<loopDataInputRef>assigneeList</loopDataInputRef>
<inputDataItem name="assignee" />
</multiInstanceLoopCharacteristics>
</userTask>
假設變數assigneeList
包含[kermit, gonzo, fozzie]
。上面的程式碼會建立三個並行的使用者任務。每一個執行都有一個名為assignee
的(區域性)流程變數,含有集合中的一項,並在這個例子中被用於指派使用者任務。
loopDataInputRef
與inputDataItem
的缺點是名字很難記,並且由於BPMN 2.0概要的限制,不能使用表示式。Flowable通過在multiInstanceCharacteristics
上提供collection與elementVariable屬性解決了這些問題:
<userTask id="miTasks" name="My Task" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="true"
flowable:collection="${myService.resolveUsersForTask()}" flowable:elementVariable="assignee" >
</multiInstanceLoopCharacteristics>
</userTask>
請注意collection
屬性會作為表示式進行解析。如果表示式解析為字串而不是一個集合,不論是因為本身配置的就是靜態字串值,還是表示式計算結果為字串,這個字串都會被當做變數名,在流程變數中用於獲取實際的集合。
例如,下面的程式碼片段會讓引擎查詢儲存在assigneeList
流程變數中的集合:
<userTask id="miTasks" name="My Task" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="true"
flowable:collection="assigneeList" flowable:elementVariable="assignee" >
</multiInstanceLoopCharacteristics>
</userTask>
1.7.3.4 條件型數量
多例項活動在所有例項都完成時結束。然而,也可以指定一個表示式,在每個例項結束時進行計算。當表示式計算為true時,將銷燬所有剩餘的例項,並結束多例項活動,繼續執行流程。這個表示式必須通過completionCondition子元素定義。
<userTask id="miTasks" name="My Task" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false"
flowable:collection="assigneeList" flowable:elementVariable="assignee" >
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6 }</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
在這個例子裡,會為assigneeList
集合中的每個元素建立並行例項。當60%的任務完成時,其他的任務將被刪除,流程繼續執行。
二、整合擴充套件的任務型別
Flowable還有很多整合擴充套件型的任務,這類任務並不常用,初學讀者可以略過,在需要時再回頭查閱。
2.1 手動任務
2.1.1 描述
手動任務(manual task)用來定義在BPM引擎不能完成的任務。對於引擎來說,手動任務將當做一個空任務來處理,在流程執行到達手動任務時,自動繼續執行流程。
2.1.2 圖示
手動任務用左上角有一個小“手”圖示的標準BPMN 2.0任務(圓角矩形)表示。
2.1.3 XML表示
<manualTask id="myManualTask" name="Call client for more information" />
2.2 Java接收任務
2.2.1 描述
接收任務(receive task),是等待特定訊息到達的簡單任務。當流程執行到達接收任務時,將保持等待狀態,直到引擎接收到特定的訊息,觸發流程穿過接收任務繼續執行。
2.2.2 圖示
接收任務用左上角有一個訊息圖示的標準BPMN 2.0任務(圓角矩形)表示。訊息圖示是白色的(對應的黑色訊息圖示代表傳送的含義)。
2.2.3 XML表示
<receiveTask id="waitState" name="wait" />
2.2.4 使用方法
要使流程例項從接收任務的等待狀態中繼續執行,需要使用到達接收任務的執行id,呼叫runtimeService.signal(executionId)。下面的程式碼片段展示瞭如何操作:
ProcessInstance pi = runtimeService.startProcessInstanceByKey("receiveTask");
Execution execution = runtimeService.createExecutionQuery()
.processInstanceId(pi.getId())
.activityId("waitState")
.singleResult();
runtimeService.trigger(execution.getId());
2.3 Shell任務
2.3.1 描述
Shell任務(Shell task)可以執行Shell指令碼與命令。請注意Shell任務不是BPMN 2.0規範的“官方”任務(因此也沒有專用圖示)。
2.3.2 定義Shell任務
Shell任務實現為特殊的服務任務,將服務任務的type定義為'shell'進行設定。
<serviceTask id="shellEcho" flowable:type="shell">
2.3.3 Shell任務引數
Shell任務通過欄位注入配置。這些引數的值可以使用EL表示式,將在流程執行執行時解析。可以設定下列引數:
| ---------------------------------------------------------------------------------------------------------------------------- |
| | 引數 | 必填? | 型別 | 描述 | 預設值 | |
| | :---------------- | :---- | :--------- | :----------------------------------------------------------- | :--------------- | |
| | command | 是 | String | 要執行的Shell命令。 | | |
| | arg0-5 | 否 | String | 引數0至引數5 | | |
| | wait | 否 | true/false | 是否等待Shell程式終止。 | true | |
| | redirectError | 否 | true/false | 是否將標準錯誤(standard error)併入標準輸出(standard output)。 | false | |
| | cleanEnv | 否 | true/false | 是否避免Shell程式繼承當前環境。 | false | |
| | outputVariable | 否 | String | 儲存輸出的變數名 | 不會記錄輸出。 | |
| | errorCodeVariable | 否 | String | 儲存結果錯誤碼的變數名 | 不會記錄錯誤碼。 | |
| | directory | 否 | String | Shell程式的預設目錄 | 當前目錄 | |
2.3.4 使用示例
下面的XML程式碼片段是使用Shell任務的例子。將會執行"cmd /c echo EchoTest" Shell指令碼,等待其結束,並將其結果存入resultVar。
<serviceTask id="shellEcho" flowable:type="shell" >
<extensionElements>
<flowable:field name="command" stringValue="cmd" />
<flowable:field name="arg1" stringValue="/c" />
<flowable:field name="arg2" stringValue="echo" />
<flowable:field name="arg3" stringValue="EchoTest" />
<flowable:field name="wait" stringValue="true" />
<flowable:field name="outputVariable" stringValue="resultVar" />
</extensionElements>
</serviceTask>
2.4 補償處理器
2.4.1 描述
如果要使用一個活動補償另一個活動的影響,可以將其宣告為補償處理器(compensation handler)。補償處理器不在正常流程中執行,而只在流程丟擲補償事件時才會執行。
補償處理器不得有入口或出口順序流。
補償處理器必須通過單向的連線,關聯一個補償邊界事件。
2.4.2 圖示
如果一個活動是補償處理器,則會在其下部中間顯示補償事件圖示。下面摘錄的流程圖展示了一個帶有補償邊界事件的服務任務,並關聯至一個補償處理器。請注意補償處理器圖示顯示在"cancel hotel reservation(取消酒店預訂)"服務任務的下部中間。
2.4.3 XML表示
要將一個活動宣告為補償處理器,需要將isForCompensation
屬性設定為true:
<serviceTask id="undoBookHotel" isForCompensation="true" flowable:class="...">
</serviceTask>
2.5 整合類任務
-
Web Service任務:呼叫外部的Web Service資源。
-
郵件任務:用於傳送郵件。
-
Http任務:用於發出Http請求。
-
Camel任務:整合訊息路由框架Camel。
-
Mule任務:整合企業系統匯流排框架Mule。
上面的整合類任務在後續篇章中會詳細介紹整合內容,此處瞭解即可。
三、小結
本篇介紹了BPMN2.0規範下及Flowable自定義擴充套件的任務型別,Flowable提供的多種任務型別基本覆蓋企業應用的需求。但還有不少問題需要我們關注,比如指令碼任務中的指令碼安全和多例項中的執行緒安全。