Spring cloud和流程引擎activiti5整合代码二,事件网关,定时事件和信号事件
参考https://blog.****.net/risheng****/article/details/90480771,前一章内容简述了如何搭建一个流程引擎框架。
这章讲述如何使用定时事件和信号事件构建一个异步的服务业务。
源代码下载地址:https://download.****.net/download/risheng****/11200394
参考业务流程图如下:
流程启动以后,会进入一个循环等待的定时任务中,每10秒执行一次黑名单规则的业务逻辑。等待无限次,直到业务流程获得一个信号blackRule,此时会结束业务的死循环,进入下一个业务获取黑名单结果的业务逻辑,并且最终结束。
这张业务流程图有几个关键点,首先是事件网关:
一.事件网关
什么是事件网关?
基于事件的网关,允许基于事件做选择。
事件网关的执行原理?
网关的每一条出口顺序流,都需要连接至一个捕获中间事件。当流程执行到达基于事件的网关时,网关类似等待状态地动作:执行被暂停。并且,为每一条出口顺序流,创建一个事件订阅。流程的走向完全是由于中间事件的选择。而由哪一个事件来决定流程的走向则是由最先触发的事件来决定的。
事件网关和其他网关的区别
请注意基于事件的网关,其出口顺序流与一般的顺序流不同。这些顺序流从不实际被执行。相反,它们允许流程引擎决定,当执行到达一个基于事件的网关时,需要订阅什么事件。
约束:
1)一个基于事件的网关,必须有两条或更多的出口顺序流。
2)基于事件的网关,只能连接至 intermediateCatchEvent(捕获中间事件) 类型的元素(Activiti不支持基于事件的网关后,连接接收任务,Receive Task)。
3)连接至基于事件的网关的 intermediateCatchEvent ,必须只有一个入口顺序流。
二,定时事件
定时器事件是根据指定的时间触发的事件。可以用于 开始事件, 中间事件 或 边界事件。
定时事件的规则可以参考手册,此处的例子是要求业务等待10秒钟。据说还可以设置cron表达式指定timeCycle。
启用定时事件需要修改activiti.cfg.xml或者Spring的applicationContext-activiti.xml,将 <property name="jobExecutorActivate" value="true" />。否则定时事件是无法触发的。
三,信号事件
信号事件会引用一个已命名的信号。信号全局范围的事件(广播语义)。 会发送给所有**的处理器。
信号事件定义使用signalEventDefinition
元素。 signalRef
属性会引用definitions
根节点里定义的signal
子元素。
此处例子订阅了blackRule信号。没有信号,业务流程永远不会结束。
下面是部分代码说明:
===========================================================================
流程配置文件:7OWxvczjpzt.bpmn20.xml
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<signal id="blackRule" name="blackRule" activiti:scope="global"></signal>
<process id="OWxvczjpzt" name="定时任务和信号事件" isExecutable="true">
<startEvent id="start" name="开始"></startEvent>
<endEvent id="end" name="结束"></endEvent>
<intermediateCatchEvent id="pMPxWV" name="定时事件">
<timerEventDefinition>
<timeDuration>PT10S</timeDuration>
</timerEventDefinition>
</intermediateCatchEvent>
<intermediateCatchEvent id="ZzciCj" name="信号事件">
<signalEventDefinition signalRef="blackRule"></signalEventDefinition>
</intermediateCatchEvent>
<serviceTask id="RHubdp" name="黑名单规则" activiti:delegateExpression="${blackTaskImpl1}"></serviceTask>
<serviceTask id="KYuSyK" name="获取黑名单结果" activiti:delegateExpression="${blackTaskImpl2}"></serviceTask>
<eventBasedGateway id="bpKRbj" name="事件网关"></eventBasedGateway>
<sequenceFlow id="OzDcey" sourceRef="ZzciCj" targetRef="KYuSyK"></sequenceFlow>
<sequenceFlow id="FGfrRD" sourceRef="start" targetRef="RHubdp"></sequenceFlow>
<sequenceFlow id="VhIEJx" sourceRef="KYuSyK" targetRef="end"></sequenceFlow>
<sequenceFlow id="QsFzpu" sourceRef="bpKRbj" targetRef="ZzciCj"></sequenceFlow>
<sequenceFlow id="tXdNxC" sourceRef="RHubdp" targetRef="bpKRbj"></sequenceFlow>
<sequenceFlow id="OqVbHq" name="TO 信号事件" sourceRef="bpKRbj" targetRef="ZzciCj"></sequenceFlow>
<sequenceFlow id="sndXvN" name="TO 定时事件" sourceRef="bpKRbj" targetRef="pMPxWV"></sequenceFlow>
<sequenceFlow id="WrTPFq" sourceRef="pMPxWV" targetRef="RHubdp"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_OWxvczjpzt">
<bpmndi:BPMNPlane bpmnElement="OWxvczjpzt" id="BPMNPlane_OWxvczjpzt">
<bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
<omgdc:Bounds height="30.0" width="30.0" x="135.0" y="160.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
<omgdc:Bounds height="28.0" width="28.0" x="1035.0" y="166.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="pMPxWV" id="BPMNShape_pMPxWV">
<omgdc:Bounds height="31.0" width="31.0" x="420.0" y="14.5"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="ZzciCj" id="BPMNShape_ZzciCj">
<omgdc:Bounds height="30.0" width="30.0" x="710.0" y="165.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="RHubdp" id="BPMNShape_RHubdp">
<omgdc:Bounds height="50.0" width="100.0" x="330.0" y="150.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="KYuSyK" id="BPMNShape_KYuSyK">
<omgdc:Bounds height="50.0" width="100.0" x="840.0" y="155.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="bpKRbj" id="BPMNShape_bpKRbj">
<omgdc:Bounds height="40.0" width="40.0" x="705.0" y="0.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="VhIEJx" id="BPMNEdge_VhIEJx">
<omgdi:waypoint x="940.0" y="180.0"></omgdi:waypoint>
<omgdi:waypoint x="1035.0" y="180.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="tXdNxC" id="BPMNEdge_tXdNxC">
<omgdi:waypoint x="430.0" y="152.53623188405797"></omgdi:waypoint>
<omgdi:waypoint x="711.2" y="26.200000000000003"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="WrTPFq" id="BPMNEdge_WrTPFq">
<omgdi:waypoint x="429.959246093876" y="44.4758435385221"></omgdi:waypoint>
<omgdi:waypoint x="389.5689655172414" y="150.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="FGfrRD" id="BPMNEdge_FGfrRD">
<omgdi:waypoint x="165.0" y="175.0"></omgdi:waypoint>
<omgdi:waypoint x="330.0" y="175.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="QsFzpu" id="BPMNEdge_QsFzpu">
<omgdi:waypoint x="725.0" y="40.0"></omgdi:waypoint>
<omgdi:waypoint x="725.0" y="165.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="OzDcey" id="BPMNEdge_OzDcey">
<omgdi:waypoint x="740.0" y="180.0"></omgdi:waypoint>
<omgdi:waypoint x="840.0" y="180.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="OqVbHq" id="BPMNEdge_OqVbHq">
<omgdi:waypoint x="725.0" y="40.0"></omgdi:waypoint>
<omgdi:waypoint x="725.0" y="165.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sndXvN" id="BPMNEdge_sndXvN">
<omgdi:waypoint x="705.0" y="20.0"></omgdi:waypoint>
<omgdi:waypoint x="578.0" y="20.0"></omgdi:waypoint>
<omgdi:waypoint x="566.5" y="27.0"></omgdi:waypoint>
<omgdi:waypoint x="450.99593714952755" y="29.64513121031616"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
===========================================================================
ActiviController.java增加了两个方法:
@RequestMapping(value = "/test/testFlow3", method = RequestMethod.GET)
public String testFlow3() throws Exception {
String retMsg=activiService.doTest3();
return retMsg;
}
@RequestMapping(value = "/test/testFlow4", method = RequestMethod.GET)
public String testFlow4() throws Exception {
String retMsg=activiService.doTest4();
return retMsg;
}
===========================================================================
ActiviService.java也增加了两个方法:
/**
* 启动定时任务流程
* @return
* @throws FileNotFoundException
*/
public String doTest3() throws FileNotFoundException {
// 部署流程文件
String filePath = "D:/workSpace/activiTest/src/main/resources/org/activiti/test/7OWxvczjpzt.bpmn20.xml";
FileInputStream fis = new FileInputStream(filePath);
repositoryService.createDeployment().addInputStream("userAndGroupInUserTask.bpmn", fis).deploy();// 用userAndGroupInUserTask.bpmn作为资源名称
Map<String, Object> variables = new HashMap<String, Object>();
// variables.put("blackTaskImpl1", new BlackTaskImpl1());
// variables.put("blackTaskImpl2", new BlackTaskImpl2());
// 启动流程
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("OWxvczjpzt", variables);
// 发送信号完成支付
//runtimeService.signalEventReceived("blackRule");
return "定时任务流程启动";
}
/**
* 发送信号结束定时任务死循环
* @return
* @throws FileNotFoundException
*/
public String doTest4() throws FileNotFoundException {
// 发送信号
runtimeService.signalEventReceived("blackRule");
return "信号事件发送成功";
}
===========================================================================
新增加的业务服务类1:
/**
* 服务节点执行的任务
*/
@Service(value="blackTaskImpl1")
public class BlackTaskImpl1 implements Serializable,JavaDelegate {
private int i=0;
@Override
public void execute(DelegateExecution execution) throws Exception {
// Thread.sleep(10000);
Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("message", "TO 定时事件");
i++;
if(i>3){
execution.setVariable("message", "TO 信号事件");
}else{
execution.setVariable("message", "TO 定时事件");
}
System.out.println("variavles=" + execution.getVariables());
System.out.println("事件执行次数:"+i);
}
}
===========================================================================
新增加的业务服务类2:
/**
* 服务节点执行的任务
*/
@Service(value="blackTaskImpl2")
public class BlackTaskImpl2 implements Serializable,JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
RuntimeService runtimeService = execution.getEngineServices().getRuntimeService();
TaskService taskService = execution.getEngineServices().getTaskService();
System.out.println("variavles=" + execution.getVariables());
System.out.println("信号事件执行次数:");
}
}
===========================================================================
启动注册中心和activiTest两个项目,然后访问业务地址:
http://localhost:8089/test/testFlow3
页面上的结果为:
定时任务流程启动
从后台控制台可以看到每10秒输出一下如下的日志:
variavles={message=TO 定时事件}
事件执行次数:1
variavles={message=TO 定时事件}
事件执行次数:2
variavles={message=TO 定时事件}
事件执行次数:3
等待事件越长,事件执行次数越多。说明业务已经进入死循环,在等待结束的信号。
访问业务地址:
http://localhost:8089/test/testFlow4
页面输出:
信号事件发送成功
从后台控制台看到如下结果:
variavles={message=TO 定时事件}
事件执行次数:1
variavles={message=TO 定时事件}
事件执行次数:2
variavles={message=TO 定时事件}
事件执行次数:3
variavles={message=TO 信号事件}
事件执行次数:4
variavles={message=TO 信号事件}
事件执行次数:5
variavles={message=TO 信号事件}
事件执行次数:6
variavles={message=TO 信号事件}
信号事件执行次数:
事件执行次数不再增加,说明业务流程已经结束。