专栏首页指缝阳光第十二节:Activiti6.0——四种边界事件:定时器、错误、信号、补偿

第十二节: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讲义第二版》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • UG编程手册

    准备几何(Prepare Geometry)-------------------------------(2)

    用户7505898
  • Aurora 8B/10B光口通信

    本课程内容参考XILINX 官方文档PG046(https://www.xilinx.com/support/documentation/ip_document...

    碎碎思
  • 第十一节:Activiti6.0——定时器开始事件、消息开始事件和错误开始事件介绍

    介绍: 在activiti中,事件按位置分可以有:开始事件、中间事件、边界时间、结束事件;按事件的特性区分有:捕获事件和抛出事件。除了事件,还有各种事件定义,常...

    凡人飞
  • 分布式事务处理技术之LCN

    分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

    时间静止不是简史
  • CAP理论十二年回顾:"规则"变了

    CAP理论断言任何基于网络的数据共享系统,最多只能满足数据一致性、可用性、分区容忍性三要素中的两个要素。但是通过显式处理分区情形,系统设计师可以做到优化数据一致...

    张善友
  • CAP理论十二年回顾:"规则"变了

    CAP理论断言任何基于网络的数据共享系统,最多只能满足数据一致性、可用性、分区容忍性三要素中的两个要素。但是通过显式处理分区情形,系统设计师可以做到优化数据一致...

    高爽
  • VVC视频编码标准化过程即将完成

    原文 https://bitmovin.com/compression-standards-vvc-2020/

    LiveVideoStack
  • VVC视频编码标准化过程即将完成

    原文 https://bitmovin.com/compression-standards-vvc-2020/

    LiveVideoStack
  • 【正经说】如何签订合法有效的对赌协议的分析和方法(含案例)

    对赌协议(Valuation Adjustment Mechanism,VAM),最初被翻译为“对赌协议”,或因符合国有文化很形象,一直沿用至今。但其直译意思是...

    辉哥
  • UNIX编程艺术之“文本化”

        本章的标题表达了作者的主旨:Good Protocols Make Good Practice。的确,好的协议或文件格式,会大大提升使用者的效率。这里的...

    王亚昌
  • RabbitMQ 高可用集群搭建及电商平台使用经验总结

    面向EDA(事件驱动架构)的方式来设计你的消息 AMQP routing key的设计 RabbitMQ cluster搭建 Mirror queue poli...

    王清培
  • 数据科学家节选(1)

    【节选自即将由电子工业出版社出版的《数据科学家养成手册》第一章】 什么是科学家 从我们每个人上学前班的时候,我们就开始受到各种各样的启蒙教育,哪怕是捏橡皮泥、...

    刀刀老高
  • 顶级 top 分布式事务方案的选择

    所谓的 XA 方案,即:两阶段提交,有一个事务管理器 的概念,负责协调多个数据库(资源管理器)的事务,事务管理器先问各个数据库准备好了吗?如果每个数据库都回 o...

    芋道源码
  • 谈谈对分布式事务的一点理解和解决方案

    最近,工作中要为现在的老系统做拆分和升级,刚好遇到了分布式事务、幂等控制、异步消息乱序和补偿方案等问题,刚好基于实践结合个人的看法记录一下一些方案和思路。

    本人秃顶程序员
  • 分布式系统关注点——99%的人都能看懂的「补偿」以及最佳实践

    前面几篇中z哥跟你聊了聊做「高可用」的意义,以及如何做「负载均衡」和「高可用三剑客」(熔断、限流、降级,文末会附上前文连接:))。这次,我们来聊一聊在保证对外高...

    Zachary_ZF
  • 分布式事务1

      分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在微服务架构中,几乎是无法避免的。

    用户2038589
  • fanuc加工中心基本操作学习资料

    FANUC 0i Mate-MC数控系统面板主要由三部分组成,即CRT显示屏、编辑面板及操作面板。

    用户7505898
  • 基于 Seata Saga 设计更有弹性的金融应用

    Seata 意为:Simple Extensible Autonomous Transaction Architecture,是一套一站式分布式事务解决方案,提...

    用户5397975
  • 解构首个城市级公共服务平台,依图凭什么?

    2020年,基于福州市“e 福州”平台架构及资源基础,福州市建立起城市级人脸识别公共服务平台,在此平台上建设“地铁刷脸通行”应用场景,及其他五个拓展试点应用场景...

    AI掘金志

扫码关注云+社区

领取腾讯云代金券