Spring cloud和流程引擎activiti5整合代码二,事件网关,定时事件和信号事件

参考https://blog.****.net/risheng****/article/details/90480771,前一章内容简述了如何搭建一个流程引擎框架。

这章讲述如何使用定时事件和信号事件构建一个异步的服务业务。

源代码下载地址:https://download.****.net/download/risheng****/11200394

参考业务流程图如下:

Spring cloud和流程引擎activiti5整合代码二,事件网关,定时事件和信号事件

 

流程启动以后,会进入一个循环等待的定时任务中,每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 信号事件}
信号事件执行次数:

 

事件执行次数不再增加,说明业务流程已经结束。