第十二节:Activiti6.0——四种边界事件:定时器、错误、信号、补偿

时间:2022-07-25
本文章向大家介绍第十二节:Activiti6.0——四种边界事件:定时器、错误、信号、补偿,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、概述

边界事件:边界事件属于一种特殊的中间事件。区别是: 中间事件 可以单独作为流程元素存在于流程中,而 边界事件 必须附属于某个流程元素(如任务、子流程等)。边界事件是Catching事件。

注意:补偿事件的连接线需要用association,association必须放在所有标签最后。

二、定时器边界事件

  1. 说明:定时器边界事件会在定时器时间到了之后进行触发,需要开启异步执行器(在activiti.cfg.xml中)。此处模拟一个损坏的物品首先交给初级工程师修理,定时1分钟后没有修好就给中级工程师修理
  2. 流程图
  1. 流程的xml
<process id="myProcess_1" isClosed="false" isExecutable="true"
      processType="None">
<startEvent id="startEvent1" name="StartEvent"/>
<userTask activiti:exclusive="true" id="userTask1" name="初级工程师维修"/>
<!--cancelActivity属性是触发边界事件后,原流程是否取消,为true是取消,取消是在数据库中删除对应的数据-->
<boundaryEvent attachedToRef="userTask1" cancelActivity="true" id="boundaryEvent1">
   <timerEventDefinition id="boundaryEvent1_ED_1">
      <!--定时一分钟-->
      <timeDuration>PT1M</timeDuration>
   </timerEventDefinition>
</boundaryEvent>
<endEvent id="endEvent1" name="EndEvent"/>
<userTask activiti:exclusive="true" id="userTask2" name="中级工程师维修"/>
<sequenceFlow id="_7" sourceRef="startEvent1" targetRef="userTask1"/>
<sequenceFlow id="_8" sourceRef="userTask1" targetRef="endEvent1"/>
<sequenceFlow id="_9" sourceRef="boundaryEvent1" targetRef="userTask2"/>
<sequenceFlow id="_10" sourceRef="userTask2" targetRef="endEvent1"/>
</process>
  1. 编码发布
 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
 RepositoryService repositoryService = processEngine.getRepositoryService();
 RuntimeService runtimeService = processEngine.getRuntimeService();
 TaskService taskService = processEngine.getTaskService();

 Deployment deployment = repositoryService.createDeployment().addClasspathResource("timer-boundary-event.bpmn").deploy();
 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
 ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());

 //首先由初级工程师维修
 Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
 System.out.println("当前任务:" + task.getName());

 //等定时器1分钟过完,需要比一分钟时间长,防止步骤没执行完
 Thread.sleep(100 * 1000);

 //定时器时间到了后会触发定时器边界事件,任务转到中级工程师
 task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
 System.out.println("当前任务:" + task.getName());

 processEngine.close();
 System.exit(0);
  1. 查看结果

三、错误边界事件

  1. 说明:当子流程中的ServiceTask抛出错误abc时,子流程的错误边界事件(定义错误引用为“abc”,没有具体的错误实现,则默认errorCode为引用的字符串“abc")会捕获该错误。 因此最终查询任务时是在ErrorTask
  2. bpmn图
  1. 流程xml
<process id="process1" name="process">
    <startEvent id="startEvent1" name="startEvent"></startEvent>
    <subProcess id="subProcess1" name="subProcess">
        <startEvent id="startEvent2" name="startEvent"></startEvent>
        <serviceTask id="serviceTask1" name="Throw Error Task"
                     activiti:class="com.xjf.test.delegate.ThrowErrorDelegate"></serviceTask>
        <endEvent id="endEvent1" name="endEvent"></endEvent>
        <sequenceFlow id="_1" sourceRef="startEvent2" targetRef="serviceTask1"></sequenceFlow>
        <sequenceFlow id="_2" sourceRef="serviceTask1" targetRef="endEvent1"></sequenceFlow>
    </subProcess>
    <boundaryEvent id="boundaryEvent1" attachedToRef="subProcess1" cancelActivity="false">
        <!--引入的错误引用没有定义时,则errorCode就是引用的字符串,此处为“abc”-->
        <errorEventDefinition errorRef="abc"></errorEventDefinition>
    </boundaryEvent>
    <userTask id="ErrorTask" name="ErrorTask"></userTask>
    <userTask id="EndTask" name="EndTask"></userTask>
    <endEvent id="endEvent2" name="endEvent"></endEvent>
    <sequenceFlow id="_3" sourceRef="startEvent1" targetRef="subProcess1"></sequenceFlow>
    <sequenceFlow id="_4" sourceRef="boundaryEvent1" targetRef="ErrorTask"></sequenceFlow>
    <sequenceFlow id="_5" sourceRef="subProcess1" targetRef="EndTask"></sequenceFlow>
    <sequenceFlow id="_6" sourceRef="EndTask" targetRef="endEvent2"></sequenceFlow>
</process>
  1. 委托类ThrowErrorDelegate:
String errorCode = "abc";
System.out.println("抛出错误:errorCode=" + errorCode);

throw new BpmnError(errorCode);
  1. 编码发布
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
TaskService taskService = processEngine.getTaskService();

Deployment deployment = repositoryService.createDeployment().addClasspathResource("error-boundary-event.bpmn").deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());

Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
System.out.println("当前任务:" + task.getName());

processEngine.close();
System.exit(0);
  1. 查看结果

四、信号边界事件

  1. 说明:该事件接收到指定的信号后触发,不同的是信号事件是全局的,即信号不是只在一个流程实例中传递,而是所有流程实例都是一样的(一处发信号,所有信号的边界事件都能接收)。此处测试的就是两个流程实例接收同一个信号。
  2. bpmn图
  1. 流程xml
<process id="process" isClosed="false" name="process" processType="None">
  <startEvent id="startEvent" name="startEvent"/>
   <userTask activiti:exclusive="true" id="checkContact" name="查看合同"/>
   <userTask activiti:exclusive="true" id="confirmContact" name="确认合同"/>
   <boundaryEvent attachedToRef="confirmContact" cancelActivity="true" id="boundaryEvent">
      <signalEventDefinition id="boundaryEvent_ED_1" signalRef="contactChangeSignal"/>
   </boundaryEvent>
   <userTask activiti:exclusive="true" id="contactChange" name="合同变更"/>
   <userTask activiti:exclusive="true" id="signContact" name="签订合同"/>
   <endEvent id="endEvent" name="endEvent"/>
   <sequenceFlow id="_2" sourceRef="startEvent" targetRef="checkContact"/>
   <sequenceFlow id="_3" sourceRef="checkContact" targetRef="confirmContact"/>
   <sequenceFlow id="_4" sourceRef="boundaryEvent" targetRef="contactChange"/>
   <sequenceFlow id="_5" sourceRef="contactChange" targetRef="checkContact"/>
   <sequenceFlow id="_6" sourceRef="confirmContact" targetRef="signContact"/>
   <sequenceFlow id="_7" sourceRef="signContact" targetRef="endEvent"/>
</process>
  1. 编码发布
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
TaskService taskService = processEngine.getTaskService();

Deployment deployment = repositoryService.createDeployment().addClasspathResource("signal-boundary-event.bpmn").deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();

//启动两个流程实例
ProcessInstance pInstance1 = runtimeService.startProcessInstanceById(processDefinition.getId());
ProcessInstance pInstance2 = runtimeService.startProcessInstanceById(processDefinition.getId());

//将实例一进行到确认合同
Task pInstance1Task = taskService.createTaskQuery().processInstanceId(pInstance1.getId()).singleResult();
taskService.complete(pInstance1Task.getId());
pInstance1Task = taskService.createTaskQuery().processInstanceId(pInstance1.getId()).singleResult();
System.out.println("实例一当前任务:" + pInstance1Task.getName());

//将实例二进行到确认合同
Task pInstance2Task = taskService.createTaskQuery().processInstanceId(pInstance2.getId()).singleResult();
taskService.complete(pInstance2Task.getId());
pInstance2Task = taskService.createTaskQuery().processInstanceId(pInstance2.getId()).singleResult();
System.out.println("实例二当前任务:" + pInstance2Task.getName());

//发送合同变更信号
runtimeService.signalEventReceived("change");

//根据流程定义查询任务
List<Task> list = taskService.createTaskQuery().processDefinitionId(processDefinition.getId()).list();
list.forEach(task -> System.out.println("流程实例id:" + task.getProcessInstanceId() + "----------------任务:" + task.getName()));

processEngine.close();
System.exit(0);
  1. 查看结果

五、补偿边界事件

  1. 说明:补偿边界事件的触发有两种情况:1. 事务子流程被取消时,会触发事务子流程里面的补偿边界事件。2. 使用补偿中间事件来触发,需要时Throwing事件。
  2. bpmn图
  1. 流程xml
<process id="process" isClosed="false" name="process" processType="None">
    <startEvent id="startEvent" name="startEvent"/>
    <serviceTask activiti:exclusive="true" id="transferOut" name="转出银行扣款"
                 activiti:class="com.xjf.test.delegate.TransferOutDelegate"/>
    <boundaryEvent attachedToRef="transferOut" cancelActivity="true" id="transferOutBoundary">
        <compensateEventDefinition id="transferOutBoundary_ED_1" waitForCompletion="true"/>
    </boundaryEvent>
    <!--isForCompensation需要指明是补偿事件-->
    <serviceTask activiti:exclusive="true" id="transferOutCancel" name="转出银行取消"
                 activiti:class="com.xjf.test.delegate.TransferOutCancelDelegate" isForCompensation="true"/>
    <serviceTask activiti:exclusive="true" id="transferIn" name="转入银行加款"
                 activiti:class="com.xjf.test.delegate.TransferInDelegate"/>
    <boundaryEvent attachedToRef="transferIn" cancelActivity="true" id="transferInBoundary">
        <compensateEventDefinition id="transferInBoundary_ED_1" waitForCompletion="true"/>
    </boundaryEvent>
    <serviceTask activiti:exclusive="true" id="transferInCancel" name="转入银行取消"
                 activiti:class="com.xjf.test.delegate.TransferInCancelDelegate" isForCompensation="true"/>
    <sequenceFlow id="_2" sourceRef="startEvent" targetRef="transferOut"/>
    <sequenceFlow id="_3" sourceRef="transferOut" targetRef="transferIn"/>
    <serviceTask activiti:exclusive="true" id="verifyTransfer" name="验证转账结果"
                 activiti:class="com.xjf.test.delegate.VerifyTransferDelegate"/>
    <boundaryEvent attachedToRef="verifyTransfer" cancelActivity="true" id="errorBoundary">
        <errorEventDefinition errorRef="transferError" id="errorBoundary_ED_1"/>
    </boundaryEvent>
    <intermediateThrowEvent id="intermediateThrowEvent" name="NoneThrowEvent">
        <compensateEventDefinition id="intermediateThrowEvent_ED_1" waitForCompletion="true"/>
    </intermediateThrowEvent>
    <endEvent id="normalEnd" name="正常结束"/>
    <endEvent id="compensateEnd" name="补偿结束"/>
    <sequenceFlow id="_4" sourceRef="transferIn" targetRef="verifyTransfer"/>
    <sequenceFlow id="_5" sourceRef="verifyTransfer" targetRef="normalEnd"/>
    <sequenceFlow id="_6" sourceRef="errorBoundary" targetRef="intermediateThrowEvent"/>
    <sequenceFlow id="_7" sourceRef="intermediateThrowEvent" targetRef="compensateEnd"/>
    <association associationDirection="None" id="a1" sourceRef="transferOutBoundary"
                 targetRef="transferOutCancel"/>
    <association associationDirection="None" id="a2" sourceRef="transferInBoundary"
                 targetRef="transferInCancel"/>
</process>
 

对应的委托类:

public class TransferInCancelDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        System.out.println("转入银行---取消增加金额");
    }
}

public class TransferInDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        System.out.println("转入银行---增加金额");
    }
}

public class TransferOutCancelDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        System.out.println("转出银行---取消扣减金额");
    }
}

public class TransferOutDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        System.out.println("转出银行---扣减金额");
    }
}

public class VerifyTransferDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        //从执行流中获取变量
        boolean flag = (boolean)delegateExecution.getVariable("result");

        if (flag){
            System.out.println("转账成功");
        }else {
            System.out.println("转账失败,抛出错误");
            throw new BpmnError("transferError");
        }
    }
}
  1. 编码发布
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();

Deployment deployment = repositoryService.createDeployment().addClasspathResource("compensation-boundary-event.xml").deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();

//存放变量,记录转账是否成功
Map<String,Object> vars = new HashMap<>();
vars.put("result",false);
runtimeService.startProcessInstanceById(processDefinition.getId(), vars);

processEngine.close();
System.exit(0);
  1. 查看结果
  • 变量result=false:
  • 变量result=true:

《疯狂Workflow讲义第二版》