前面和小伙伴們分別聊了 Flowable 中的 ReceiveTask 和 UserTask,今天我們來看看另外一個(gè)比較常見的 Task --> ServiceTask。
1. ServiceTask
ServiceTask 從名字上看就是服務(wù)任務(wù),它的圖標(biāo)一般是像下面這樣:

ServiceTask 一般由系統(tǒng)自動(dòng)完成,當(dāng)流程走到這一步的時(shí)候,不會(huì)自動(dòng)停下來,而是會(huì)去執(zhí)行我們提前在 ServiceTask 中配置好的方法。
2. 實(shí)踐
我們通過一個(gè)簡(jiǎn)單的例子來看一下 ServiceTask 要怎么玩。
假設(shè)我有如下一個(gè)簡(jiǎn)單的流程圖:

中間這個(gè)就是一個(gè) ServiceTask。
當(dāng)流程執(zhí)行到 ServiceTask 的時(shí)候,具體要做哪些事情?有三種不同的方式來設(shè)置這里的任務(wù),我們分別來看。
2.1 監(jiān)聽類
首先我們可以設(shè)置一個(gè)監(jiān)聽類,這個(gè)監(jiān)聽類有一個(gè)硬性規(guī)定就是需要實(shí)現(xiàn) JavaDelegate 接口,像下面這樣:
public class MyServiceTask implements JavaDelegate {
@Override
public void execute(DelegateExecution execution){
System.out.println("========MyServiceTask==========");
}
}
在這個(gè)監(jiān)聽類中我們可以完成一些操作,通過這個(gè) execution 也可以獲取到在流程節(jié)點(diǎn)之間傳輸?shù)淖兞俊?/p>
這個(gè)類定義好之后,接下來我們?cè)诹鞒潭x的時(shí)候,配置這個(gè)類的全路徑即可,如下圖:

這個(gè)配置對(duì)應(yīng)的 XML 內(nèi)容如下:
<process id="demo01" name="測(cè)試流程" isExecutable="true">
<documentation>測(cè)試流程</documentation>
<startEvent id="startEvent1" flowable:formFieldValidatinotallow="true"></startEvent>
<sequenceFlow id="sid-33A78082-C2FD-48BE-8B87-99FB20F0B331" sourceRef="startEvent1" targetRef="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8"></sequenceFlow>
<serviceTask id="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8" flowable:class="org.javaboy.flowableidm.MyServiceTask"></serviceTask>
<endEvent id="sid-A5F11956-15EA-4574-98D0-29A4E3DB5495"></endEvent>
<sequenceFlow id="sid-0698809E-0A6C-4B92-A167-AE96A8CB75F2" sourceRef="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8" targetRef="sid-A5F11956-15EA-4574-98D0-29A4E3DB5495"></sequenceFlow>
</process>
小伙伴們看到,在 ServiceTask 標(biāo)簽中的 flowable:class="org.javaboy.flowableidm.MyServiceTask" 就表示 ServiceTask 執(zhí)行的服務(wù)類。
配置完成后,我們可以部署并啟動(dòng)這個(gè)流程,由于這個(gè)流程除了開始和結(jié)束,就這一個(gè)節(jié)點(diǎn),所以流程一啟動(dòng)就自動(dòng)結(jié)束了。不過在這個(gè)過程中,我們可以看到控制臺(tái)打印出來了日志,說明這個(gè) ServiceTask 確實(shí)是執(zhí)行了。
2.2 委托表達(dá)式
我們也可以配置委托表達(dá)式。
委托表達(dá)式是指將一個(gè)實(shí)現(xiàn)了 JavaDelegate 接口的類注冊(cè)到 Spring 容器中,然后我們?cè)诹鞒坦?jié)點(diǎn)的配置中不用寫完整的類名了,只需要寫 Spring 容器中的 Bean 名稱即可。
像下面這樣:
@Component
public class MyServiceTask implements JavaDelegate {
@Override
public void execute(DelegateExecution execution){
System.out.println("========MyServiceTask==========");
}
}
這個(gè)類注冊(cè)到 Spring 容器中的默認(rèn)名稱是類名首字母小寫,即 myServiceTask。
現(xiàn)在我們?cè)诹鞒虉D中,可以按照如下方式進(jìn)行配置:

對(duì)應(yīng)的 XML 文件如下:
<process id="demo01" name="測(cè)試流程" isExecutable="true">
<documentation>測(cè)試流程</documentation>
<startEvent id="startEvent1" flowable:formFieldValidatinotallow="true"></startEvent>
<sequenceFlow id="sid-33A78082-C2FD-48BE-8B87-99FB20F0B331" sourceRef="startEvent1" targetRef="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8"></sequenceFlow>
<serviceTask id="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8" flowable:delegateExpressinotallow="${myServiceTask}"></serviceTask>
<endEvent id="sid-A5F11956-15EA-4574-98D0-29A4E3DB5495"></endEvent>
<sequenceFlow id="sid-0698809E-0A6C-4B92-A167-AE96A8CB75F2" sourceRef="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8" targetRef="sid-A5F11956-15EA-4574-98D0-29A4E3DB5495"></sequenceFlow>
</process>
可以看到,flowable:delegateExpressinotallow="${myServiceTask}" 就表示執(zhí)行的一個(gè)表達(dá)式。
測(cè)試過程同 2.1 小節(jié),我就不再贅述了。
最后總結(jié)一下,委托表達(dá)式,一定是 JavaDelegate 接口的實(shí)現(xiàn)類,將這個(gè)實(shí)現(xiàn)類注冊(cè)到 Spring 容器中,然后在使用的時(shí)候,根據(jù) Bean 的名稱從 Spring 容器中查找即可。
2.3 表達(dá)式
我們也可以使用表達(dá)式。
表達(dá)式就是一個(gè)普通類的普通方法,將這個(gè)普通類注冊(cè)到 Spring 容器中,然后表達(dá)式中還可以執(zhí)行這個(gè)類中的方法,類似下面這樣,任意定義一個(gè) Java 類:
@Component
public class MyServiceTask2 {
public void hello(){
System.out.println("========MyServiceTask2==========");
}
}
然后在流程圖中按照如下方式進(jìn)行配置:

表達(dá)式中有一部分內(nèi)容隱藏了,完整的表達(dá)式是 ${myServiceTask2.hello()}。
對(duì)應(yīng)的 XML 文件如下:
<process id="demo01" name="測(cè)試流程" isExecutable="true">
<documentation>測(cè)試流程</documentation>
<startEvent id="startEvent1" flowable:formFieldValidatinotallow="true"></startEvent>
<sequenceFlow id="sid-33A78082-C2FD-48BE-8B87-99FB20F0B331" sourceRef="startEvent1" targetRef="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8"></sequenceFlow>
<serviceTask id="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8" flowable:expressinotallow="${myServiceTask2.hello()}"></serviceTask>
<endEvent id="sid-A5F11956-15EA-4574-98D0-29A4E3DB5495"></endEvent>
<sequenceFlow id="sid-0698809E-0A6C-4B92-A167-AE96A8CB75F2" sourceRef="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8" targetRef="sid-A5F11956-15EA-4574-98D0-29A4E3DB5495"></sequenceFlow>
</process>
可以看到,表達(dá)式的內(nèi)容是 flowable:expressinotallow="${myServiceTask2.hello()}。
測(cè)試方式同 2.1 小節(jié),這里我不再贅述。
3. 類中字段
可能有小伙伴注意到,我們?cè)诶L制流程圖的時(shí)候,還可以為類設(shè)置一個(gè)字段。
例如我想給 ServiceTask 的執(zhí)行類設(shè)置一個(gè) username 字段,如下:


設(shè)置完成后,對(duì)應(yīng)的 XML 如下:
<process id="demo01" name="測(cè)試流程" isExecutable="true">
<documentation>測(cè)試流程</documentation>
<startEvent id="startEvent1" flowable:formFieldValidatinotallow="true"></startEvent>
<sequenceFlow id="sid-33A78082-C2FD-48BE-8B87-99FB20F0B331" sourceRef="startEvent1" targetRef="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8"></sequenceFlow>
<serviceTask id="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8" flowable:delegateExpressinotallow="${myServiceTask}">
<extensionElements>
<flowable:field name="username">
<flowable:string><![CDATA[javaboy]]></flowable:string>
</flowable:field>
</extensionElements>
</serviceTask>
<endEvent id="sid-A5F11956-15EA-4574-98D0-29A4E3DB5495"></endEvent>
<sequenceFlow id="sid-0698809E-0A6C-4B92-A167-AE96A8CB75F2" sourceRef="sid-6FA66E2A-F8E6-4F10-8FA2-6450408E17D8" targetRef="sid-A5F11956-15EA-4574-98D0-29A4E3DB5495"></sequenceFlow>
</process>
可以看到,這里通過 extensionElements 節(jié)點(diǎn)描述了額外的信息。
接下來,我們就可以在 Java 類中訪問到這個(gè)變量了,如下:
@Component
public class MyServiceTask implements JavaDelegate {
Expression username;
@Override
public void execute(DelegateExecution execution){
System.out.println("username.getExpressionText() = " + username.getExpressionText());
System.out.println("username.getValue(execution) = " + username.getValue(execution));
System.out.println("========MyServiceTask==========");
}
}
想要獲取到 username 對(duì)應(yīng)的值,上面這段代碼中,松哥給大家演示了兩種方式。
不過需要注意,這種設(shè)置類中字段的方式,適用于 2.1 和 2.2 小節(jié)的情況,不適用于 2.3 小節(jié)的情況。