任務是流程中最重要的組成部分。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提供的多種任務類型基本覆蓋企業應用的需求。但還有不少問題需要我們關注,比如腳本任務中的腳本安全和多實例中的線程安全。