java每日精进 7.26【流程设计5.0(中间事件+结束事件)】
1.中间事件核心概念
-
定位:位于开始事件与结束事件之间,影响流程路由但不启动/终止流程。
-
两类中间事件:
-
捕获事件(Catch):等待外部触发(如消息、信号到达)。
-
抛出事件(Throw):主动触发事件(如发送信号、抛出异常)。
-
-
与边界事件区别:边界事件附着在活动节点上,而中间事件独立存在于连线上。
1.1 中间抛出事件
1. 空中间抛出事件
-
作用:流程状态标记点,通过监听器执行自定义逻辑。
-
XML示例:
<process id="noneEventProcess"> <intermediateThrowEvent id="statusMarker"> <extensionElements> <flowable:executionListener event="start" class="com.example.ProcessStatusListener"/> <!-- 监听状态变更 --> </extensionElements> </intermediateThrowEvent> </process> -
使用场景:记录流程进入关键节点(如"订单已审核"),触发数据库日志记录。
-
定义创建了一个简单流程,其中包含一个无类型中间抛出事件,当流程执行到这个事件时,会触发指定的 Java 类(
MyExecutionListener)中的逻辑。这种模式通常用于在流程执行过程中插入自定义业务逻辑、发送通知或与外部系统交互等场景。
2. 信号中间抛出事件
在流程执行过程中发送特定消息的机制
实例说明
具体实例
假设我们有一个订单处理流程,当订单确认后需要向支付系统发送支付请求,这就是消息中间抛出事件的典型应用场景。
BPMN 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"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100524/BPMN20.xsd"
id="Definitions_1"
targetNamespace="http://camunda.org/examples">
<!-- 定义消息 -->
<message id="paymentRequestMsg" name="订单支付请求" />
<message id="paymentResponseMsg" name="支付结果响应" />
<!-- 订单流程 - 包含消息中间抛出事件 -->
<process id="orderProcess" name="订单处理流程" isExecutable="true">
<startEvent id="start" />
<sequenceFlow id="flow1" sourceRef="start" targetRef="confirmOrder" />
<userTask id="confirmOrder" name="确认订单" />
<sequenceFlow id="flow2" sourceRef="confirmOrder" targetRef="sendPaymentRequest" />
<!-- 消息中间抛出事件:发送支付请求 -->
<intermediateThrowEvent id="sendPaymentRequest">
<messageEventDefinition messageRef="paymentRequestMsg" />
</intermediateThrowEvent>
<sequenceFlow id="flow3" sourceRef="sendPaymentRequest" targetRef="waitPaymentResponse" />
<!-- 消息中间捕获事件:等待支付响应 -->
<intermediateCatchEvent id="waitPaymentResponse">
<messageEventDefinition messageRef="paymentResponseMsg" />
</intermediateCatchEvent>
<sequenceFlow id="flow4" sourceRef="waitPaymentResponse" targetRef="end" />
<endEvent id="end" />
</process>
<!-- 支付流程 - 接收支付请求 -->
<process id="paymentProcess" name="支付处理流程" isExecutable="true">
<!-- 消息开始事件:接收支付请求 -->
<startEvent id="paymentStart">
<messageEventDefinition messageRef="paymentRequestMsg" />
</startEvent>
<sequenceFlow id="flow5" sourceRef="paymentStart" targetRef="processPayment" />
<serviceTask id="processPayment" name="处理支付" />
<sequenceFlow id="flow6" sourceRef="processPayment" targetRef="sendPaymentResponse" />
<!-- 消息中间抛出事件:发送支付响应 -->
<intermediateThrowEvent id="sendPaymentResponse">
<messageEventDefinition messageRef="paymentResponseMsg" />
</intermediateThrowEvent>
<sequenceFlow id="flow7" sourceRef="sendPaymentResponse" targetRef="paymentEnd" />
<endEvent id="paymentEnd" />
</process>
</definitions>
// 1. 部署流程定义
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
.addClasspathResource("order-payment-process.bpmn20.xml")
.deploy();
// 2. 启动订单流程
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance orderProcessInstance = runtimeService.startProcessInstanceByKey("orderProcess");
System.out.println("订单流程已启动,ID: " + orderProcessInstance.getId());
// 3. 完成"确认订单"任务
TaskService taskService = processEngine.getTaskService();
Task confirmTask = taskService.createTaskQuery()
.processInstanceId(orderProcessInstance.getId())
.singleResult();
taskService.complete(confirmTask.getId());
// 此时流程会执行到sendPaymentRequest节点,发送支付请求消息
// 支付流程会自动启动并处理支付(因为有消息开始事件)
// 4. 模拟支付完成后,发送支付响应消息
// 查找等待支付响应的执行实例
Execution execution = runtimeService.createExecutionQuery()
.processInstanceId(orderProcessInstance.getId())
.messageEventSubscriptionName("paymentResponseMsg")
.singleResult();
// 发送响应消息
runtimeService.messageEventReceived("paymentResponseMsg", execution.getId());
System.out.println("支付响应已发送,订单流程将继续执行");
-
作用:全局广播信号,触发所有匹配的信号捕获事件(包括开始/边界/中间事件)。
-
XML定义:
<signal id="alertSignal" name="紧急告警" /> <!-- 信号定义 --> <process id="signalProcess"> <intermediateThrowEvent id="throwAlert"> <signalEventDefinition signalRef="alertSignal" /> <!-- 抛出信号 --> </intermediateThrowEvent> </process> -
触发效果:
-
并行流程中订阅了
alertSignal的信号边界事件会中断当前任务。 -
信号开始事件启动新流程实例。
-
-
消息中间抛出事件
- 是 BPMN 中的一种事件类型,用于在流程执行到特定节点时主动发送消息
- 实现的是点对点通信模式,需要有明确的消息接收方
- 通常用于不同流程之间或流程与外部系统之间的通信
-
XML 定义解析
<message>标签:定义消息元数据,id是唯一标识,name是可读名称<intermediateThrowEvent>标签:定义中间抛出事件<messageEventDefinition>标签:将事件与特定消息关联,messageRef引用消息的id
-
接收机制
- 必须有对应的消息捕获事件(如消息中间捕获事件或消息边界事件)来接收此消息
- 形成了 "发送 - 接收" 的消息传递模式
- 整个流程包含两个子流程:订单处理流程和支付处理流程
- 订单流程在确认订单后,通过 "消息中间抛出事件" 发送支付请求
- 支付流程通过 "消息开始事件" 接收支付请求并处理
- 支付完成后,支付流程通过另一个 "消息中间抛出事件" 发送支付响应
- 订单流程通过 "消息中间捕获事件" 等待并接收支付响应,然后继续执行后续流程
实例说明
- 整个流程包含两个子流程:订单处理流程和支付处理流程
- 订单流程在确认订单后,通过 "消息中间抛出事件" 发送支付请求
- 支付流程通过 "消息开始事件" 接收支付请求并处理
- 支付完成后,支付流程通过另一个 "消息中间抛出事件" 发送支付响应
- 订单流程通过 "消息中间捕获事件" 等待并接收支付响应,然后继续执行后续流程
3. 消息中间抛出事件
-
作用:向特定接收方发送消息(点对点通信)。
-
XML定义:
<message id="paymentMsg" name="支付请求" /> <!-- 消息定义 --> <process id="paymentProcess"> <intermediateThrowEvent id="sendPayment"> <messageEventDefinition messageRef="paymentMsg" /> <!-- 抛出消息 --> </intermediateThrowEvent> </process> -
接收方:必须存在对应的消息捕获事件(如消息中间捕获事件)。
-
实例:
// 外部系统通过API触发消息 runtimeService.messageEventReceived("paymentMsg", executionId);流程在
sendPayment节点暂停,直到外部系统调用此API。 -
xml示例
<!-- 消息中间抛出事件:发送支付请求 --> <intermediateThrowEvent id="sendPaymentRequest"> <messageEventDefinition messageRef="paymentRequestMsg" /> </intermediateThrowEvent> <sequenceFlow id="flow3" sourceRef="sendPaymentRequest" targetRef="waitPaymentResponse" /> <!-- 消息中间捕获事件:等待支付响应 --> <intermediateCatchEvent id="waitPaymentResponse"> <messageEventDefinition messageRef="paymentResponseMsg" /> </intermediateCatchEvent>
4. 补偿中间抛出事件
-
作用:用于在流程出现异常或需要取消操作时,触发已完成活动的补偿逻辑,恢复到之前的状态。
-
XML定义:
<intermediateThrowEvent id="undoActions"> <compensateEventDefinition /> <!-- 触发补偿 --> </intermediateThrowEvent>
-
XML 定义解析
<intermediateThrowEvent id="undoActions">:定义补偿中间抛出事件<compensateEventDefinition />:标识这是一个补偿事件,用于触发补偿逻辑
-
补偿规则:
- 触发补偿:当流程执行到补偿中间抛出事件时,会触发已完成活动的补偿处理器
- 事务回滚:用于撤销之前的操作,恢复系统状态
- 补偿处理器:为需要补偿的活动定义的撤销逻辑(如取消订单、退款等)
-
补偿规则详解
- 反向触发:按活动完成顺序的逆序执行补偿(最后完成的活动最先补偿)
- 作用域限制:仅补偿同一子流程层级中定义了补偿处理器的活动
- 多实例活动:需等待所有实例都完成后才会触发补偿
-
补偿处理器定义
- 通过边界事件
<boundaryEvent>定义,需指定attachedToRef关联到需要补偿的活动 - 包含
<compensateEventDefinition />标识这是一个补偿处理器
- 通过边界事件
-
实例:
<?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:flowable="http://flowable.org/bpmn" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100524/BPMN20.xsd http://flowable.org/bpmn http://flowable.org/bpmn/current/flowable-bpmn.xsd" id="Definitions_1" targetNamespace="http://flowable.org/examples"> <process id="travelBookingProcess" name="旅行预订流程" isExecutable="true"> <startEvent id="start" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="bookFlight" /> <!-- 预订航班服务任务 --> <serviceTask id="bookFlight" name="预订航班" flowable:class="com.example.BookFlightService"> <extensionElements> <flowable:executionListener event="end" class="com.example.LogFlightBookingListener" /> </extensionElements> </serviceTask> <!-- 航班预订的补偿处理器 --> <boundaryEvent id="compensateFlight" attachedToRef="bookFlight" cancelActivity="false"> <compensateEventDefinition /> </boundaryEvent> <!-- 补偿航班预订的服务任务 --> <serviceTask id="undoFlightBooking" name="取消航班预订" flowable:class="com.example.CancelFlightBookingService"> <extensionElements> <flowable:executionListener event="end" class="com.example.LogFlightCancellationListener" /> </extensionElements> </serviceTask> <sequenceFlow id="flow2" sourceRef="compensateFlight" targetRef="undoFlightBooking" /> <sequenceFlow id="flow3" sourceRef="undoFlightBooking" targetRef="compensationEnd" /> <sequenceFlow id="flow4" sourceRef="bookFlight" targetRef="bookHotel" /> <!-- 预订酒店服务任务 --> <serviceTask id="bookHotel" name="预订酒店" flowable:class="com.example.BookHotelService"> <extensionElements> <flowable:executionListener event="end" class="com.example.LogHotelBookingListener" /> </extensionElements> </serviceTask> <!-- 酒店预订的补偿处理器 --> <boundaryEvent id="compensateHotel" attachedToRef="bookHotel" cancelActivity="false"> <compensateEventDefinition /> </boundaryEvent> <!-- 补偿酒店预订的服务任务 --> <serviceTask id="undoHotelBooking" name="取消酒店预订" flowable:class="com.example.CancelHotelBookingService"> <extensionElements> <flowable:executionListener event="end" class="com.example.LogHotelCancellationListener" /> </extensionElements> </serviceTask> <sequenceFlow id="flow5" sourceRef="compensateHotel" targetRef="undoHotelBooking" /> <sequenceFlow id="flow6" sourceRef="undoHotelBooking" targetRef="compensationEnd" /> <sequenceFlow id="flow7" sourceRef="bookHotel" targetRef="paymentCheck" /> <!-- 检查支付状态网关 --> <exclusiveGateway id="paymentCheck" /> <!-- 支付成功路径 --> <sequenceFlow id="flow8" sourceRef="paymentCheck" targetRef="bookingSuccess"> <conditionExpression xsi:type="tFormalExpression">${paymentSuccessful == true}</conditionExpression> </sequenceFlow> <!-- 支付失败路径 - 触发补偿 --> <sequenceFlow id="flow9" sourceRef="paymentCheck" targetRef="undoActions"> <conditionExpression xsi:type="tFormalExpression">${paymentSuccessful == false}</conditionExpression> </sequenceFlow> <!-- 补偿中间抛出事件 --> <intermediateThrowEvent id="undoActions"> <compensateEventDefinition /> </intermediateThrowEvent> <sequenceFlow id="flow10" sourceRef="undoActions" targetRef="compensationEnd" /> <!-- 预订成功结束事件 --> <endEvent id="bookingSuccess" /> <!-- 补偿完成结束事件 --> <endEvent id="compensationEnd" /> </process> </definitions>// 部署流程 repositoryService.createDeployment() .addClasspathResource("travel-booking-process.bpmn20.xml") .deploy(); // 启动流程实例 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("travelBookingProcess"); // 模拟支付失败的情况 Task paymentTask = taskService.createTaskQuery() .processInstanceId(processInstance.getId()) .taskName("检查支付状态") .singleResult(); // 设置支付失败变量 Map<String, Object> variables = new HashMap<>(); variables.put("paymentSuccessful", false); taskService.complete(paymentTask.getId(), variables); // 此时流程会执行到undoActions节点,触发补偿 // 补偿顺序:先取消酒店预订(后完成的活动),再取消航班预订(先完成的活动)实例执行流程说明
-
正常流程:
- 开始 → 预订航班 → 预订酒店 → 检查支付状态 → 支付成功 → 流程结束
-
补偿触发流程(当支付失败时):
- 开始 → 预订航班 → 预订酒店 → 检查支付状态 → 支付失败 → 触发补偿中间事件 (undoActions)
- 补偿执行顺序(反向执行):
- 触发酒店预订的补偿处理器 → 执行取消酒店预订
- 触发航班预订的补偿处理器 → 执行取消航班预订
- 补偿完成 → 流程结束
5. 升级中间抛出事件(Escalation)
-
作用:向父流程传递异常(非错误),不中断当前流程。
-
基本作用
- 跨层级通知:向父流程传递特定事件信息
- 非中断性:抛出事件后,当前流程(子流程)继续执行
- 异常传递:用于传递需要上级处理的特殊情况(非错误)
-
XML 定义解析
<intermediateThrowEvent id="escalateIssue">:定义升级中间抛出事件<escalationEventDefinition escalationRef="managerApproval" />:关联到特定升级定义,escalationRef引用升级事件的 ID
-
工作机制
- 子流程中定义升级抛出事件
- 父流程中需定义对应的升级捕获事件(通常是边界事件)
- 事件触发后,父流程执行相应处理,子流程继续原有路径
-
与错误事件的关键区别
- 错误事件:抛出后会终止当前流程路径,通常用于处理异常情况
- 升级事件:仅向上传递信息,不影响当前流程执行,用于需要上级关注的业务情况
-
详细实例:采购审批流程
-
<?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:flowable="http://flowable.org/bpmn" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100524/BPMN20.xsd http://flowable.org/bpmn http://flowable.org/bpmn/current/flowable-bpmn.xsd" id="Definitions_1" targetNamespace="http://flowable.org/examples"> <!-- 定义升级事件 --> <escalation id="managerApproval" name="需要经理审批" /> <!-- 父流程:采购管理流程 --> <process id="purchaseManagementProcess" name="采购管理流程" isExecutable="true"> <startEvent id="parentStart" /> <sequenceFlow id="flow1" sourceRef="parentStart" targetRef="subProcess" /> <!-- 子流程:采购审批流程 --> <subProcess id="subProcess" name="采购审批流程"> <startEvent id="subStart" /> <sequenceFlow id="flow2" sourceRef="subStart" targetRef="checkAmount" /> <!-- 检查采购金额 --> <serviceTask id="checkAmount" name="检查采购金额" flowable:class="com.example.CheckPurchaseAmountService" /> <sequenceFlow id="flow3" sourceRef="checkAmount" targetRef="amountGateway" /> <!-- 金额判断网关 --> <exclusiveGateway id="amountGateway" /> <!-- 金额正常路径 --> <sequenceFlow id="flow4" sourceRef="amountGateway" targetRef="departmentApproval"> <conditionExpression xsi:type="tFormalExpression">${amount <= 10000}</conditionExpression> </sequenceFlow> <!-- 金额超限路径 - 触发升级 --> <sequenceFlow id="flow5" sourceRef="amountGateway" targetRef="escalateIssue"> <conditionExpression xsi:type="tFormalExpression">${amount > 10000}</conditionExpression> </sequenceFlow> <!-- 升级中间抛出事件 --> <intermediateThrowEvent id="escalateIssue"> <escalationEventDefinition escalationRef="managerApproval" /> </intermediateThrowEvent> <sequenceFlow id="flow6" sourceRef="escalateIssue" targetRef="departmentApproval" /> <!-- 部门审批 --> <userTask id="departmentApproval" name="部门审批" /> <sequenceFlow id="flow7" sourceRef="departmentApproval" targetRef="subEnd" /> <endEvent id="subEnd" /> </subProcess> <!-- 父流程中捕获升级事件的边界事件 --> <boundaryEvent id="catchEscalation" attachedToRef="subProcess"> <escalationEventDefinition escalationRef="managerApproval" /> </boundaryEvent> <sequenceFlow id="flow8" sourceRef="catchEscalation" targetRef="notifyManager" /> <!-- 通知经理处理 --> <serviceTask id="notifyManager" name="通知经理" flowable:class="com.example.NotifyManagerService" /> <sequenceFlow id="flow9" sourceRef="notifyManager" targetRef="parentEnd" /> <sequenceFlow id="flow10" sourceRef="subProcess" targetRef="parentEnd" /> <endEvent id="parentEnd" /> </process> </definitions>Java 代码实现示例:
- 检查采购金额的服务类:
-
public class CheckPurchaseAmountService implements JavaDelegate { @Override public void execute(DelegateExecution execution) { // 获取采购金额(实际应用中从流程变量获取) double amount = (double) execution.getVariable("purchaseAmount"); System.out.println("检查采购金额: " + amount); // 设置金额变量用于网关判断 execution.setVariable("amount", amount); } } - 通知经理的服务类:
-
public class NotifyManagerService implements JavaDelegate { @Override public void execute(DelegateExecution execution) { double amount = (double) execution.getVariable("amount"); String purchaseId = (String) execution.getVariable("purchaseId"); System.out.println("发送通知给经理: 采购单 " + purchaseId + " 金额为 " + amount + ",超过审批阈值需要关注"); // 实际应用中这里会发送邮件、消息等 } }
// 部署流程定义
repositoryService.createDeployment()
.addClasspathResource("purchase-approval-process.bpmn20.xml")
.deploy();
// 启动流程实例,设置采购金额为15000(超过10000阈值)
Map<String, Object> variables = new HashMap<>();
variables.put("purchaseId", "PO-" + System.currentTimeMillis());
variables.put("purchaseAmount", 15000.00);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
"purchaseManagementProcess", variables);
// 完成部门审批任务
Task departmentTask = taskService.createTaskQuery()
.processInstanceId(processInstance.getId())
.taskName("部门审批")
.singleResult();
taskService.complete(departmentTask.getId());
实例执行流程说明
-
正常执行路径:
- 父流程启动 → 进入子流程 → 检查采购金额(15000 元)
- 金额超过阈值(10000 元)→ 触发升级中间抛出事件 (escalateIssue)
- 子流程继续执行 → 部门审批 → 子流程结束 → 父流程结束
-
升级事件处理路径(并行发生):
- 升级事件触发 → 父流程的边界事件 (catchEscalation) 捕获事件
- 执行通知经理服务 → 完成经理通知流程
-
关键特性体现:
- 升级事件不中断子流程,子流程继续完成部门审批
- 父流程同时处理升级事件,发送通知给经理
- 实现了 "异常情况上报" 但 "业务继续处理" 的业务需求
注:父子事件联系如下:
<!-- 父流程中的子流程节点 -->
<subProcess id="subProcess" name="采购审批流程">
<!-- 子流程内部逻辑(包含升级抛出事件) -->
</subProcess>
<!-- 绑定到子流程的升级边界事件 -->
<boundaryEvent id="catchEscalation" attachedToRef="subProcess">
<!-- 关联到子流程抛出的升级事件ID -->
<escalationEventDefinition escalationRef="managerApproval" />
</boundaryEvent>
关键区别总结
| 事件类型 | 方向 | 触发方式 | 作用范围 |
|---|---|---|---|
| 信号抛出 | 抛出 | 全局广播 | 跨流程实例 |
| 消息抛出 | 抛出 | 点对点发送 | 指定接收方 |
| 补偿抛出 | 抛出 | 触发补偿处理器 | 当前作用域 |
| 信号/消息捕获 | 捕获 | 等待外部触发 | 当前流程节点 |
| 计时器捕获 | 捕获 | 时间到达后自动触发 | 当前节点 |
最佳实践建议
-
空事件:结合监听器实现审计日志或指标统计。
-
信号事件:跨流程协同(如主流程通知子流程)。
-
消息事件:与外部系统集成(如等待支付回调)。
-
补偿事件:实现SAGA事务模式,确保数据一致性。
-
升级事件:构建分层异常处理机制(子流程→父流程)。
1.2 中间捕获事件
1. 计时器中间捕获事件
-
作用:延迟等待(如"3天后继续")。
-
<intermediateCatchEvent id="wait3Days"> <timerEventDefinition> <timeDuration>PT72H</timeDuration> <!-- 等待72小时 --> </timerEventDefinition> </intermediateCatchEvent> - 实例展示
-
<?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" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100524/BPMN20.xsd" id="Definitions_1" targetNamespace="http://example.org"> <process id="leaveRequestProcess" name="假期申请流程" isExecutable="true"> <startEvent id="start" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="submitRequest" /> <!-- 员工提交假期申请 --> <userTask id="submitRequest" name="提交假期申请" /> <sequenceFlow id="flow2" sourceRef="submitRequest" targetRef="managerApproval" /> <!-- 经理审批 --> <userTask id="managerApproval" name="经理审批" /> <sequenceFlow id="flow3" sourceRef="managerApproval" targetRef="end" /> <!-- 绑定到经理审批的边界事件:如果超时未审批则触发 --> <boundaryEvent id="approvalTimeout" attachedToRef="managerApproval"> <!-- 计时器中间捕获事件定义:等待3天(72小时) --> <timerEventDefinition> <timeDuration>PT72H</timeDuration> <!-- 时间格式:PT代表时间周期,72H表示72小时 --> </timerEventDefinition> </boundaryEvent> <sequenceFlow id="flow4" sourceRef="approvalTimeout" targetRef="sendReminder" /> <!-- 发送审批提醒 --> <serviceTask id="sendReminder" name="发送审批提醒" /> <sequenceFlow id="flow5" sourceRef="sendReminder" targetRef="managerApproval" /> <endEvent id="end" /> </process> </definitions>流程说明:
- 员工提交假期申请后,流程进入 "经理审批" 环节
- 同时,绑定在审批环节上的计时器开始计时(等待 72 小时)
- 如果经理在 3 天内完成审批,流程直接结束
- 如果 3 天内未审批,计时器事件触发,执行 "发送审批提醒"
- 发送提醒后,流程回到 "经理审批" 环节,等待经理处理
2. 信号/消息中间捕获事件
信号 / 消息中间捕获事件是 BPMN 中用于接收外部信号或消息的机制,与对应的抛出事件配合使用,实现流程间或流程与外部系统的异步通信。其中:
- 消息中间捕获事件:接收特定的点对点消息,通常用于两个明确流程之间的通信
- 信号中间捕获事件:接收广播式信号,可被多个流程实例同时捕获
两者均会使流程暂停,等待对应的事件触发后再继续执行。
消息中间捕获事件实例:订单支付流程
以下是一个电商订单流程的示例,订单创建后会等待支付系统发送的支付完成消息,收到消息后才继续后续的发货流程。
<?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:flowable="http://flowable.org/bpmn"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100524/BPMN20.xsd http://flowable.org/bpmn http://flowable.org/bpmn/current/flowable-bpmn.xsd"
id="Definitions_1"
targetNamespace="http://flowable.org/examples">
<!-- 定义支付消息 -->
<message id="paymentMsg" name="支付完成消息" />
<!-- 订单处理流程 -->
<process id="orderProcess" name="订单处理流程" isExecutable="true">
<startEvent id="start" />
<sequenceFlow id="flow1" sourceRef="start" targetRef="createOrder" />
<!-- 创建订单 -->
<serviceTask id="createOrder" name="创建订单" flowable:class="com.example.CreateOrderService" />
<sequenceFlow id="flow2" sourceRef="createOrder" targetRef="waitPayment" />
<!-- 消息中间捕获事件:等待支付完成消息 -->
<intermediateCatchEvent id="waitPayment">
<messageEventDefinition messageRef="paymentMsg" />
</intermediateCatchEvent>
<sequenceFlow id="flow3" sourceRef="waitPayment" targetRef="arrangeDelivery" />
<!-- 安排发货 -->
<serviceTask id="arrangeDelivery" name="安排发货" flowable:class="com.example.ArrangeDeliveryService" />
<sequenceFlow id="flow4" sourceRef="arrangeDelivery" targetRef="end" />
<endEvent id="end" />
</process>
<!-- 支付处理流程 -->
<process id="paymentProcess" name="支付处理流程" isExecutable="true">
<startEvent id="paymentStart" />
<sequenceFlow id="flow5" sourceRef="paymentStart" targetRef="processPayment" />
<!-- 处理支付 -->
<serviceTask id="processPayment" name="处理支付" flowable:class="com.example.ProcessPaymentService" />
<sequenceFlow id="flow6" sourceRef="processPayment" targetRef="sendPaymentMsg" />
<!-- 消息中间抛出事件:发送支付完成消息 -->
<intermediateThrowEvent id="sendPaymentMsg">
<messageEventDefinition messageRef="paymentMsg" />
</intermediateThrowEvent>
<sequenceFlow id="flow7" sourceRef="sendPaymentMsg" targetRef="paymentEnd" />
<endEvent id="paymentEnd" />
</process>
</definitions>
Java 代码实现示例:
- 创建订单服务类:
public class CreateOrderService implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
String orderId = "ORDER-" + System.currentTimeMillis();
execution.setVariable("orderId", orderId);
System.out.println("订单创建成功,订单ID: " + orderId);
// 实际业务中会保存订单信息到数据库
}
}
- 处理支付服务类:
public class ProcessPaymentService implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
String orderId = (String) execution.getVariable("orderId");
System.out.println("处理订单 " + orderId + " 的支付...");
// 实际业务中会调用支付网关处理支付
execution.setVariable("paymentStatus", "SUCCESS");
}
}
- 流程交互代码:
// 1. 部署流程
repositoryService.createDeployment()
.addClasspathResource("order-payment-process.bpmn20.xml")
.deploy();
// 2. 启动订单流程
Map<String, Object> orderVariables = new HashMap<>();
ProcessInstance orderInstance = runtimeService.startProcessInstanceByKey("orderProcess", orderVariables);
String orderId = (String) runtimeService.getVariable(orderInstance.getId(), "orderId");
System.out.println("订单流程已启动,等待支付,订单ID: " + orderId);
// 3. 启动支付流程,传入订单ID
Map<String, Object> paymentVariables = new HashMap<>();
paymentVariables.put("orderId", orderId);
ProcessInstance paymentInstance = runtimeService.startProcessInstanceByKey("paymentProcess", paymentVariables);
// 4. 支付完成后,发送支付消息给订单流程
// 查找等待支付消息的执行实例
Execution waitingExecution = runtimeService.createExecutionQuery()
.processInstanceId(orderInstance.getId())
.messageEventSubscriptionName("paymentMsg")
.singleResult();
// 发送消息触发订单流程继续执行
runtimeService.messageEventReceived("paymentMsg", waitingExecution.getId());
System.out.println("支付完成消息已发送,订单流程将继续执行");
实例执行流程说明
- 订单流程启动后,创建订单并执行到
waitPayment节点 - 此时订单流程暂停,等待
paymentMsg消息 - 支付流程启动并处理支付,完成后通过
sendPaymentMsg节点抛出paymentMsg消息 - 调用
runtimeService.messageEventReceived()方法将消息传递给订单流程 - 订单流程的
waitPayment节点捕获到消息,继续执行后续的发货流程
关键特性总结
- 消息捕获事件与抛出事件通过
messageRef关联,必须引用同一个消息 ID - 流程会在消息捕获事件处暂停,直到收到对应的消息才继续
- 消息是点对点的,通常用于两个特定流程之间的通信
- 适用于需要异步等待外部系统响应的场景(如支付、审批等)
2.结束事件
2.1 空结束事件(None End Event)

2.1.1 解释
- 定义:空结束事件是 Flowable 中最常见且最简单的结束事件。它用于标记流程或分支的结束,且不抛出任何特定结果。当流程实例或分支到达空结束事件时,流程引擎会终止该流程实例或分支。如果流程实例有多个并行分支,只有当所有分支都到达空结束事件时,整个流程实例才会结束。
- 特点:
- 不处理抛出结果,相当于流程或分支的“正常结束”。
- 适用于流程或分支的常规终止场景,无需额外的操作。
- 使用场景:通常用于流程的自然结束,例如订单处理完成后结束流程。
2.1.2 图形标记
- 空结束事件在 BPMN 图中表现为一个粗边圆圈,内部没有图标,表示无特定结果类型。
- 示例图形(文字描述):end-event(粗边圆圈,无内部图标)。
2.1.3 XML 表示
- 空结束事件的 XML 定义非常简单,仅包含 <endEvent> 标签,无子元素。
- 示例代码:
<endEvent id="endEvent1" name="noneEndEvent"></endEvent>- id:事件的唯一标识符。
- name:事件的显示名称(可选)。
2.1.4 使用示例
- 场景:一个简单的订单处理流程,包含下单、支付和发货步骤,支付成功后到达空结束事件,流程结束。
- 流程描述:用户下单后,流程进入支付节点,支付成功后到达空结束事件,流程实例终止。
- XML 示例:
<process id="simpleOrderProcess" name="简单订单流程" isExecutable="true"> <startEvent id="startEvent" /> <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="orderTask" /> <userTask id="orderTask" name="下单" /> <sequenceFlow id="flow2" sourceRef="orderTask" targetRef="paymentTask" /> <userTask id="paymentTask" name="支付" /> <sequenceFlow id="flow3" sourceRef="paymentTask" targetRef="endEvent" /> <endEvent id="endEvent" name="noneEndEvent" /> </process>- 说明:流程从 startEvent 开始,经过 orderTask(下单)和 paymentTask(支付),最后到达 endEvent,结束流程。
2.2 错误结束事件(Error End Event)

2.2.1 解释
- 定义:错误结束事件在流程到达时抛出错误,并终止当前流程分支。它通常用于子流程中,抛出的错误会被父流程的错误边界事件捕获。错误结束事件需要定义一个错误码(errorRef),以便与错误边界事件匹配。
- 特点:
- 抛出特定错误码,触发对应的错误边界事件。
- 仅适用于子流程,父流程通过错误边界事件处理抛出的错误。
- 使用场景:常用于异常处理,例如支付失败时触发重新支付的逻辑。
2.2.2 图形标记
- 错误结束事件表现为一个粗边圆圈,内部包含一个全黑错误图标(类似闪电形状),表示抛出错误。
- 示例图形(文字描述):end-event(粗边圆圈,内部有全黑错误图标)。
2.2.3 XML 表示
- 错误结束事件的 XML 定义包含 <endEvent> 标签和 <errorEventDefinition> 子元素,errorRef 属性引用流程中定义的错误。
- 示例代码:
<error id="theError" /><process id="errorEndEventProcess"><endEvent id="myErrorEndEvent"><errorEventDefinition errorRef="theError" /></endEvent></process>- <error>:定义错误,id 为错误标识。
- <errorEventDefinition>:指定抛出的错误,errorRef 引用错误标识。
2.2.4 使用示例
- 场景:一个订单流程包含支付子流程。如果支付失败,子流程到达错误结束事件,抛出错误,触发父流程的错误边界事件,重新启动支付子流程;如果支付成功,子流程到达空结束事件,继续到发货节点。
- 流程描述:
- 用户下单。
- 进入支付子流程。
- 支付成功:到达空结束事件,子流程结束,进入发货。
- 支付失败:到达错误结束事件,抛出错误,触发错误边界事件,重新进入支付子流程。
- XML 示例(简化版,基于文档提供的内容):
<error id="payError" errorCode="payErrorCode" /> <process id="ErrorEndEventProcess" name="错误结束事件" isExecutable="true"> <startEvent id="startEvent" /> <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="orderTask" /> <userTask id="orderTask" name="下单" /> <sequenceFlow id="flow2" sourceRef="orderTask" targetRef="paymentSubProcess" /> <subProcess id="paymentSubProcess" name="付款子流程"> <startEvent id="subStartEvent" /> <sequenceFlow id="subFlow1" sourceRef="subStartEvent" targetRef="paymentTask" /> <userTask id="paymentTask" name="付款" /> <sequenceFlow id="subFlow2" sourceRef="paymentTask" targetRef="gateway" /> <exclusiveGateway id="gateway" /> <sequenceFlow id="successFlow" name="支付成功" sourceRef="gateway" targetRef="noneEndEvent"> <conditionExpression xsi:type="tFormalExpression">${payResult == true}</conditionExpression> </sequenceFlow> <endEvent id="noneEndEvent" /> <sequenceFlow id="errorFlow" name="支付失败" sourceRef="gateway" targetRef="errorEndEvent"> <conditionExpression xsi:type="tFormalExpression">${payResult == false}</conditionExpression> </sequenceFlow> <endEvent id="errorEndEvent"> <errorEventDefinition errorRef="payError" /> </endEvent> </subProcess> <sequenceFlow id="flow3" sourceRef="paymentSubProcess" targetRef="deliveryTask" /> <userTask id="deliveryTask" name="发货" /> <sequenceFlow id="flow4" sourceRef="deliveryTask" targetRef="endEvent" /> <endEvent id="endEvent" /> <boundaryEvent id="errorBoundaryEvent" attachedToRef="paymentSubProcess"> <errorEventDefinition errorRef="payError" /> </boundaryEvent> <sequenceFlow id="retryFlow" name="重新付款" sourceRef="errorBoundaryEvent" targetRef="paymentSubProcess" /> </process>- 说明:支付子流程 (paymentSubProcess) 中,支付失败时到达 errorEndEvent,抛出 payError 错误,被父流程的 errorBoundaryEvent 捕获,重新流转到 paymentSubProcess。
2.3 取消结束事件(Cancel End Event)

2.3.1 解释
- 定义:取消结束事件专用于 BPMN 事务子流程(Transaction Subprocess)。当到达取消结束事件时,抛出取消事件,必须由事务子流程上的取消边界事件捕获。捕获后,事务被取消,并触发补偿机制(compensation)来回滚相关操作。
- 特点:
- 仅在事务子流程中使用。
- 抛出取消事件,触发取消边界事件和补偿机制。
- 常与补偿事件一起使用,用于事务回滚场景。
- 使用场景:适用于需要事务一致性的场景,例如订单取消后需要释放库存或退款。
2.3.2 图形标记
- 取消结束事件表现为一个粗边圆圈,内部包含一个全黑取消图标(通常为“X”形状)。
- 示例图形(文字描述):cancel-end-event(粗边圆圈,内部有全黑取消图标)。
2.3.3 XML 表示
- 取消结束事件的 XML 定义包含 <endEvent> 标签和 <cancelEventDefinition> 子元素。
- 示例代码:
<process id="cancelEndEventProcess"><endEvent id="cancelEndEvent"><cancelEventDefinition /></endEvent></process>- <cancelEventDefinition>:表示取消事件,无需额外属性。
2.3.4 使用示例
- 场景:一个系统上线事务子流程,包含人工上线任务。如果上线失败,到达取消结束事件,触发取消边界事件,执行自动回滚补偿,并流转到用户排查任务。
- 流程图描述(文字说明):
- 流程启动 → 用户提交订单 → 事务子流程(锁定库存 → 支付)。
- 支付成功 → 空结束事件 → 发货 → 结束。
- 用户取消订单 → 取消结束事件 → 触发取消边界事件 → 补偿(释放库存、退款) → 自动取消订单 → 结束。
- XML 示例:
<process id="CompleteTransactionSubProcess" name="完整事务子流程" isExecutable="true"> <!-- 错误定义 --> <error id="errorFlag" errorCode="500" /> <!-- 主流程 --> <startEvent id="startEvent" /> <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="submitOrderTask" /> <userTask id="submitOrderTask" name="用户提交订单"> <extensionElements> <flowable:formData /> <flowable:assigneeType>static</flowable:assigneeType> </extensionElements> </userTask> <sequenceFlow id="flow2" sourceRef="submitOrderTask" targetRef="transactionSubProcess" /> <!-- 事务子流程 --> <transaction id="transactionSubProcess" name="订单处理事务"> <startEvent id="subStartEvent" /> <sequenceFlow id="subFlow1" sourceRef="subStartEvent" targetRef="lockInventoryTask" /> <serviceTask id="lockInventoryTask" name="锁定库存" flowable:class="com.example.LockInventoryService"> <extensionElements> <flowable:formData /> <flowable:assigneeType>static</flowable:assigneeType> </extensionElements> </serviceTask> <sequenceFlow id="subFlow2" sourceRef="lockInventoryTask" targetRef="paymentTask" /> <userTask id="paymentTask" name="用户支付订单"> <extensionElements> <flowable:formData /> <flowable:assigneeType>static</flowable:assigneeType> </extensionElements> </userTask> <sequenceFlow id="subFlow3" sourceRef="paymentTask" targetRef="gateway" /> <exclusiveGateway id="gateway" /> <!-- 正常路径:支付成功 --> <sequenceFlow id="successFlow" name="支付成功" sourceRef="gateway" targetRef="deductInventoryTask"> <conditionExpression xsi:type="tFormalExpression">${payResult == true}</conditionExpression> </sequenceFlow> <serviceTask id="deductInventoryTask" name="扣减库存" flowable:class="com.example.DeductInventoryService" /> <sequenceFlow id="subFlow4" sourceRef="deductInventoryTask" targetRef="noneEndEvent" /> <endEvent id="noneEndEvent" /> <!-- 取消路径:用户取消订单 --> <sequenceFlow id="cancelFlow" name="用户取消" sourceRef="gateway" targetRef="cancelEndEvent"> <conditionExpression xsi:type="tFormalExpression">${payResult == false}</conditionExpression> </sequenceFlow> <endEvent id="cancelEndEvent"> <cancelEventDefinition /> </endEvent> <!-- 补偿任务 --> <serviceTask id="releaseInventoryTask" name="释放库存" isForCompensation="true" flowable:class="com.example.ReleaseInventoryService" /> <serviceTask id="refundTask" name="费用退回" isForCompensation="true" flowable:class="com.example.RefundService" /> <boundaryEvent id="compensateInventoryEvent" attachedToRef="lockInventoryTask"> <compensateEventDefinition /> </boundaryEvent> <boundaryEvent id="compensatePaymentEvent" attachedToRef="paymentTask"> <compensateEventDefinition /> </boundaryEvent> <association id="assoc1" associationDirection="One" sourceRef="compensateInventoryEvent" targetRef="releaseInventoryTask" /> <association id="assoc2" associationDirection="One" sourceRef="compensatePaymentEvent" targetRef="refundTask" /> </transaction> <!-- 取消边界事件 --> <boundaryEvent id="cancelBoundaryEvent" attachedToRef="transactionSubProcess"> <cancelEventDefinition /> </boundaryEvent> <sequenceFlow id="flow3" sourceRef="cancelBoundaryEvent" targetRef="cancelOrderTask" /> <serviceTask id="cancelOrderTask" name="自动取消订单" flowable:class="com.example.CancelOrderService"> <extensionElements> <flowable:formData /> <flowable:assigneeType>static</flowable:assigneeType> </extensionElements> </serviceTask> <sequenceFlow id="flow4" sourceRef="cancelOrderTask" targetRef="endEventCancel" /> <endEvent id="endEventCancel" /> <!-- 正常路径继续 --> <sequenceFlow id="flow5" sourceRef="transactionSubProcess" targetRef="deliveryTask" /> <userTask id="deliveryTask" name="发货"> <extensionElements> <flowable:formData /> <flowable:assigneeType>static</flowable:assigneeType> </extensionElements> </userTask> <sequenceFlow id="flow6" sourceRef="deliveryTask" targetRef="endEventSuccess" /> <endEvent id="endEventSuccess" /> </process> - 正常路径:
- 从 subStartEvent 开始,执行 lockInventoryTask(锁定库存)和 paymentTask(支付)。
- 支付成功(payResult == true),通过 gateway 流向 deductInventoryTask(扣减库存),到达 noneEndEvent,事务子流程结束,进入主流程的 deliveryTask(发货)。
- 取消路径:
- 用户取消订单(payResult == false),通过 gateway 流向 cancelEndEvent,抛出取消事件。
- cancelBoundaryEvent 捕获取消事件,触发补偿任务(releaseInventoryTask 和 refundTask),释放库存并退款。
- 流程流向 cancelOrderTask(自动取消订单),最终到达 endEventCancel。
- 补偿机制:
- releaseInventoryTask 和 refundTask 标记为 isForCompensation="true",通过 compensateEventDefinition 关联到对应的任务,确保取消时回滚操作。
- 图示
[主流程]
|
▼
[Start Event] ----> [UserTask: 用户提交订单]
| name="submitOrderTask"
| id="submitOrderTask"
▼
[Transaction Subprocess: 订单处理事务] ----> [UserTask: 发货] ----> [End Event]
id="transactionSubProcess" name="deliveryTask" id="endEventSuccess"
| id="deliveryTask"
▼
[Start Event] ----> [ServiceTask: 锁定库存] ----> [UserTask: 用户支付订单] ----> [Exclusive Gateway]
id="subStartEvent" name="lockInventoryTask" name="paymentTask" id="gateway"
id="lockInventoryTask" id="paymentTask"
flowable:class="com.example.LockInventoryService"
输出参数: payResult (boolean)
|
| payResult == true
▼
[ServiceTask: 扣减库存] ----> [None End Event]
name="deductInventoryTask" id="noneEndEvent"
id="deductInventoryTask"
flowable:class="com.example.DeductInventoryService"
|
| payResult == false
▼
[Cancel End Event] ----> [触发 Cancel Boundary Event]
id="cancelEndEvent" id="cancelBoundaryEvent"
<cancelEventDefinition /> attachedTo="transactionSubProcess"
|
| [Compensate Boundary Event] ----> [ServiceTask: 释放库存]
| id="compensateInventoryEvent" name="releaseInventoryTask"
| attachedTo="lockInventoryTask" isForCompensation="true"
| flowable:class="com.example.ReleaseInventoryService"
|
| [Compensate Boundary Event] ----> [ServiceTask: 费用退回]
| id="compensatePaymentEvent" name="refundTask"
| attachedTo="paymentTask" isForCompensation="true"
| flowable:class="com.example.RefundService"
|
▼
[Cancel Boundary Event] ----> [ServiceTask: 自动取消订单] ----> [End Event]
id="cancelBoundaryEvent" name="cancelOrderTask" id="endEventCancel"
attachedTo="transactionSubProcess" id="cancelOrderTask"
<cancelEventDefinition /> flowable:class="com.example.CancelOrderService"
2.3.5 注意事项
- 取消结束事件只能用于事务子流程。
- 必须有取消边界事件捕获取消事件。
- 取消事件需要配合补偿机制,否则会抛出异常(如 FlowableException: No execution found for sub process of boundary cancel event)。
2.4 终止结束事件(Terminate End Event)

2.4.1 解释
- 定义:终止结束事件用于强制终止整个流程或其所在的范围(scope,如子流程或主流程)。当流程到达终止结束事件时,流程引擎会终止当前范围内的所有活动,包括并行分支。如果在子流程中,终止范围由 terminateAll 属性决定。
- 特点:
- 可终止整个流程或仅当前子流程。
- terminateAll="true":终止整个根流程实例,无论事件位置。
- terminateAll="false"(默认):仅终止当前子流程或实例。
- 使用场景:适用于需要立即停止所有流程活动的场景,例如紧急取消订单。
2.4.2 图形标记
- 终止结束事件表现为一个粗边圆圈,内部包含一个全黑实心圆图标。
- 示例图形(文字描述):terminate-end-event(粗边圆圈,内部有全黑实心圆)。
2.4.3 XML 表示
- 终止结束事件的 XML 定义包含 <endEvent> 标签和 <terminateEventDefinition> 子元素,flowable:terminateAll 属性控制终止范围。
- 示例代码:
<endEvent id="terminateEndEvent"><terminateEventDefinition flowable:terminateAll="true" /></endEvent>- flowable:terminateAll:可选,true 表示终止整个流程,false 表示仅终止当前范围。
2.4.4 使用示例
- 场景:一个订单流程包含并行分支(支付和库存锁定)。如果用户取消订单,到达终止结束事件,立即终止所有分支,流程结束。
- 流程描述:
- 流程启动,进入并行网关,分为支付和库存锁定两个分支。
- 用户取消订单,到达终止结束事件,终止所有分支,流程结束。
- XML 示例:
<process id="terminateEndEventProcess" name="终止结束事件" isExecutable="true"> <startEvent id="startEvent" /> <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="orderTask" /> <userTask id="orderTask" name="下单" /> <sequenceFlow id="flow2" sourceRef="orderTask" targetRef="parallelGateway" /> <parallelGateway id="parallelGateway" /> <sequenceFlow id="flow3" sourceRef="parallelGateway" targetRef="paymentTask" /> <userTask id="paymentTask" name="支付" /> <sequenceFlow id="flow4" sourceRef="paymentTask" targetRef="noneEndEvent" /> <endEvent id="noneEndEvent" /> <sequenceFlow id="flow5" sourceRef="parallelGateway" targetRef="lockTask" /> <serviceTask id="lockTask" name="锁定库存" flowable:class="com.example.LockService" /> <sequenceFlow id="flow6" sourceRef="lockTask" targetRef="cancelTask" /> <userTask id="cancelTask" name="取消订单" /> <sequenceFlow id="flow7" sourceRef="cancelTask" targetRef="terminateEndEvent" /> <endEvent id="terminateEndEvent"> <terminateEventDefinition flowable:terminateAll="true" /> </endEvent> </process>- 说明:流程通过 parallelGateway 分出支付和库存锁定分支。如果用户在 cancelTask 取消订单,到达 terminateEndEvent,设置 terminateAll="true",整个流程(包括支付分支)立即终止。
2.4.5 注意事项
- terminateAll="true" 会终止整个流程实例,适用于需要强制停止所有活动的场景。
- terminateAll="false" 仅终止当前子流程,适合局部终止场景。
总结
- 空结束事件:最简单的结束事件,用于流程或分支的正常结束,无需抛出结果。
- 错误结束事件:用于子流程抛出错误,触发父流程的错误边界事件,适合异常处理。
- 取消结束事件:专用于事务子流程,触发取消边界事件和补偿机制,适合事务回滚。
- 终止结束事件:强制终止流程或子流程,适合紧急停止场景,范围由 terminateAll 属性控制。
- 共同点:所有结束事件均为“抛出”事件,区别在于抛出结果的类型和处理方式。
更多推荐
所有评论(0)