java每日精进 7.25【流程设计3.0(网关+边界事件)】
1.网关
在BPMN 2.0(业务流程建模与标记法)中,网关是用来控制流程走向的元素,就像路口的红绿灯或岔路口,用来决定流程接下来该走哪条路。它的图形是一个菱形,内部有不同的小图标,表示不同类型的网关。网关可以用来拆分流程(一条路分成多条)或合并流程(多条路汇成一条),主要用于处理复杂的流程逻辑。
Flowable(一个基于BPMN 2.0的流程引擎)中常用的网关有四种:
- 排他网关(Exclusive Gateway):只能选一条路走。
- 并行网关(Parallel Gateway):可以同时走多条路或等待多条路汇合。
- 包容网关(Inclusive Gateway):可以根据条件走多条路或等待部分路汇合。
- 事件网关(Event Gateway):根据事件触发来选择走哪条路。
1.1 排他网关(Exclusive Gateway)
定义
排他网关(也叫XOR网关)是最常用的网关,作用是做选择题:从多条路中只能选一条走。它需要搭配条件来判断走哪条路,条件写在流出顺序流(sequenceFlow)上。
- 工作原理:
- 流程到达排他网关时,会按顺序检查每条流出顺序流的条件。
- 找到第一个条件为true的顺序流,就走这条路,其他路被忽略。
- 如果所有条件都为false,但定义了默认顺序流,就走默认路。
- 如果没有默认路且所有条件都为false,流程会抛出异常(流程中断)。
- 建议每条顺序流都设置条件,没条件的顺序流默认算true。
- 排他网关不负责合并,只要有一个流入的顺序流到达,它就开始判断走哪条路。如果有多个分支到达,可能会重复执行后续路径(除非业务需要,否则要避免)。
图形标记
排他网关是一个菱形,里面有个**“X”**图标,表示“异或”(XOR,意思是“只能选一个”)。
XML代码
排他网关的XML定义很简单,只需要指定ID和默认顺序流(如果有):
<exclusiveGateway id="Gateway_1gse3sj" default="Flow_1gdshzv"/>
条件写在流出顺序流中,比如:
<sequenceFlow id="Flow_0mdfhgf" name="大于10000" sourceRef="Gateway_1gse3sj" targetRef="Activity_1gvbrzi">
<conditionExpression xsi:type="tFormalExpression">
${money>10000}
</conditionExpression>
</sequenceFlow>
代码示例解析
以下是文中给出的排他网关流程示例(简化后的流程:费用申请审批):
<process id="ServiceSpringCloudBackServiceProcess" name="服务-Springcloud回调服务" isExecutable="true"><startEvent id="a39b8c7712bb742a7aa081cf731563c96" /><userTask id="ad7ca5657f18f4e64aa6e309db12fc47b" name="费用申请" /><sequenceFlow id="a653af6d1d2774d02afc0301d2f0121e2" sourceRef="a39b8c7712bb742a7aa081cf731563c96" targetRef="ad7ca5657f18f4e64aa6e309db12fc47b" /><exclusiveGateway id="Gateway_1gse3sj" default="Flow_1gdshzv"><incoming>Flow_0tmo406</incoming><outgoing>Flow_1gdshzv</outgoing><outgoing>Flow_0mdfhgf</outgoing></exclusiveGateway><userTask id="Activity_0b7092y" name="经理" /><userTask id="Activity_1gvbrzi" name="总监" /><userTask id="Activity_0ol5zjn" name="总经理" /><endEvent id="Event_1vogsar" /><sequenceFlow id="Flow_0tmo406" sourceRef="ad7ca5657f18f4e64aa6e309db12fc47b" targetRef="Gateway_1gse3sj" /><sequenceFlow id="Flow_1gdshzv" sourceRef="Gateway_1gse3sj" targetRef="Activity_0b7092y" /><sequenceFlow id="Flow_0mdfhgf" name="大于10000" sourceRef="Gateway_1gse3sj" targetRef="Activity_1gvbrzi"><conditionExpression xsi:type="tFormalExpression">${money>10000}</conditionExpression></sequenceFlow><sequenceFlow id="Flow_0c58ztv" sourceRef="Activity_0b7092y" targetRef="Activity_1gvbrzi" /><sequenceFlow id="Flow_0ovnf34" sourceRef="Activity_1gvbrzi" targetRef="Activity_0ol5zjn" /><sequenceFlow id="Flow_0odeyuq" sourceRef="Activity_0ol5zjn" targetRef="Event_1vogsar" /></process>
流程解释
这是一个费用申请审批流程:
- 开始事件:流程从startEvent开始。
- 费用申请:员工提交费用申请(userTask: 费用申请)。
- 排他网关:流程到达exclusiveGateway: Gateway_1gse3sj,需要判断申请金额:
- 如果金额大于10000(Flow_0mdfhgf条件:${money>10000}),走总监审批(userTask: 总监)。
- 否则,走默认路径(Flow_1gdshzv),由经理审批(userTask: 经理)。
- 后续审批:
- 经理审批后,进入总监审批。
- 总监审批后,进入总经理审批(userTask: 总经理)。
- 结束:总经理审批后,流程到达endEvent,结束。
现实场景
想象你在公司报销一笔费用:
- 你提交报销申请(比如报销5000元或15000元)。
- 系统检查金额:
- 如果金额≤10000元,报销单给经理审批。
- 如果金额>10000元,报销单直接给总监审批。
- 经理审批后,报销单交给总监;总监审批后,交给总经理。
- 最后由总经理决定是否通过。
关键点
- 排他网关确保只有一条路被选中。
- 条件${money>10000}是基于流程变量money判断的,变量值由用户或系统设置。
- 默认路径(Flow_1gdshzv)保证即使条件不满足,流程也不会中断。
1.2 并行网关(Parallel Gateway)
定义
并行网关(也叫AND网关)用来处理并发,可以把流程拆成多条同时执行的路(分支,Fork),也可以把多条路汇合到一起(合并,Join)。它不看条件,所有流出的路都会走,所有流入的路都要到齐。
- 分支(Fork):从并行网关流出后,每条顺序流都会生成一个并发分支,所有分支同时执行,忽略顺序流上的条件。
- 合并(Join):所有流入并行网关的分支必须都到达,网关才会继续向下走。如果有分支没到,网关就一直等待。
- 多进多出:一个并行网关可以同时分支和合并,先合并所有流入分支,再拆分成多个并发分支。
图形标记
并行网关是一个菱形,里面有个**“+”**图标,表示“与”(AND,意思是“所有都执行”)。
XML代码
<parallelGateway id="parallelGateway1" />
行为(分支或合并)由流入和流出顺序流决定。
现实场景
假设公司要开发一个产品:
- 分支:产品开发需要同时进行“前端开发”和“后端开发”,并行网关将流程拆成两条路,两个团队同时开工。
- 合并:只有当“前端开发”和“后端开发”都完成后,才能进入“测试”阶段。并行网关会等待两支团队都完成。
代码示例
<parallelGateway id="ForkGateway" /><sequenceFlow id="Flow1" sourceRef="ForkGateway" targetRef="Task_Frontend" /><sequenceFlow id="Flow2" sourceRef="ForkGateway" targetRef="Task_Backend" /><userTask id="Task_Frontend" name="前端开发" /><userTask id="Task_Backend" name="后端开发" /><sequenceFlow id="Flow3" sourceRef="Task_Frontend" targetRef="JoinGateway" /><sequenceFlow id="Flow4" sourceRef="Task_Backend" targetRef="JoinGateway" /><parallelGateway id="JoinGateway" />
- ForkGateway:将流程拆分成“前端开发”和“后端开发”两条并发路径。
- JoinGateway:等待两支团队完成任务后,流程继续。
关键点
- 并行网关不检查条件,所有流出路径都会执行。
- 合并时必须所有分支都到达,否则流程卡住。
- 不要求分支和合并成对出现,一个分支网关可以对应多个合并网关,或无需合并。
1.3 包容网关(Inclusive Gateway)
定义
包容网关是排他网关和并行网关的结合体,可以根据条件选择多条路同时走(分支),也可以等待部分分支汇合(合并)。它比排他网关灵活,比并行网关有条件控制。
- 分支(Fork):
- 检查所有流出顺序流的条件,所有条件为true的路径都会并行执行。
- 如果所有条件都为false,但有默认路径,就走默认路径。
- 如果没有默认路径且所有条件为false,抛出异常。
- 合并(Join):
- 等待所有“可以到达”网关的分支都到达,才继续向下走。
- “可以到达”是指:流程实例中存在一条路径能到达网关(忽略条件)。
- 比如,如果某个分支压根没被触发,网关不会等它。
- 多进多出:可以同时合并和分支,先合并所有可到达的流入分支,再根据条件拆分成多个并行分支。
图形标记
包容网关是一个菱形,里面有个圆圈图标。
XML代码
<inclusiveGateway id="inclusiveGateway1" />
代码示例解析
以下是文中给出的包容网关流程示例(请假审批流程):
<process id="InclusiveGatewayTest" name="网关-包容网关" isExecutable="true"><startEvent id="a63caeb191435462eb8fc789b998b0b02" /><userTask id="a2a3d2965e93841769298862145315216" name="请假申请" /><sequenceFlow id="a10afa5b876a14ef1927568c25d82532d" sourceRef="a63caeb191435462eb8fc789b998b0b02" targetRef="a2a3d2965e93841769298862145315216" /><inclusiveGateway id="Gateway_0wdovry" /><sequenceFlow id="Flow_01gl4se" sourceRef="a2a3d2965e93841769298862145315216" targetRef="Gateway_0wdovry" /><userTask id="Activity_0n2utd2" name="HR实习生审批" /><sequenceFlow id="Flow_0poec43" name="天数<3" sourceRef="Gateway_0wdovry" targetRef="Activity_0n2utd2"><conditionExpression xsi:type="tFormalExpression">${leaveDays<3}</conditionExpression></sequenceFlow><userTask id="Activity_1jqu87g" name="HR助理审批" /><sequenceFlow id="Flow_048awuq" name="天数>=3" sourceRef="Gateway_0wdovry" targetRef="Activity_1jqu87g"><conditionExpression xsi:type="tFormalExpression">${leaveDays>=3}</conditionExpression></sequenceFlow><userTask id="Activity_0i4f84q" name="直属领导审批" /><sequenceFlow id="Flow_1ifcgzs" name="天数>=1" sourceRef="Gateway_0wdovry" targetRef="Activity_0i4f84q"><conditionExpression xsi:type="tFormalExpression">${leaveDays>=1}</conditionExpression></sequenceFlow><inclusiveGateway id="Gateway_1byuti3" /><sequenceFlow id="Flow_0evatt3" sourceRef="Activity_0n2utd2" targetRef="Gateway_1byuti3" /><sequenceFlow id="Flow_1t3shqg" sourceRef="Activity_1jqu87g" targetRef="Gateway_1byuti3" /><userTask id="Activity_1ox2rws" name="HR经理审批" /><sequenceFlow id="Flow_0tc6xkx" sourceRef="Gateway_1byuti3" targetRef="Activity_1ox2rws" /><inclusiveGateway id="Gateway_02v0l7w" /><sequenceFlow id="Flow_0o8l6c2" sourceRef="Activity_1ox2rws" targetRef="Gateway_02v0l7w" /><sequenceFlow id="Flow_0s50mvn" sourceRef="Activity_0i4f84q" targetRef="Gateway_02v0l7w" /><endEvent id="Event_0cvo3tf" /><sequenceFlow id="Flow_120xxfs" sourceRef="Gateway_02v0l7w" targetRef="Event_0cvo3tf" /></process>
流程解释
这是一个请假审批流程:
- 开始事件:员工提交请假申请(userTask: 请假申请)。
- 第一个包容网关(Gateway_0wdovry):根据请假天数(leaveDays)决定走哪些审批路径:
- 如果leaveDays < 3,需要HR实习生审批(userTask: HR实习生审批)。
- 如果leaveDays >= 3,需要HR助理审批(userTask: HR助理审批)。
- 如果leaveDays >= 1,需要直属领导审批(userTask: 直属领导审批)。
- 比如,员工请5天假,条件leaveDays>=3和leaveDays>=1都满足,流程会同时走HR助理审批和直属领导审批两条路。
- 第二个包容网关(Gateway_1byuti3):等待HR实习生审批和HR助理审批(如果触发了)完成,合并后进入HR经理审批(userTask: HR经理审批)。
- 第三个包容网关(Gateway_02v0l7w):等待HR经理审批和直属领导审批(如果触发了)完成,流程结束。
现实场景
假设你请假:
- 请2天假:触发HR实习生审批(leaveDays<3)和直属领导审批(leaveDays>=1)。
- 请5天假:触发HR助理审批(leaveDays>=3)和直属领导审批(leaveDays>=1)。
- 流程会等待触发了的审批都完成,再交给HR经理审批,最后由HR经理和直属领导的审批结果决定是否通过。
关键点
- 包容网关允许多条路径并行,根据条件决定走哪些路。
- 合并时只等“可以到达”的分支,比如请2天假时,HR助理审批没触发,网关不会等它。
- 建议设置默认路径,避免所有条件为false导致流程中断。
1.4 事件网关(Event Gateway)
定义
事件网关根据事件来决定走哪条路,而不是条件。它会暂停流程,等待某个事件(如定时器、消息)触发,然后走触发事件的路径,其他路径被取消。
- 工作原理:
- 事件网关的每个流出顺序流必须连接到一个中间捕获事件(如定时器事件、信号事件)。
- 到达网关时,流程暂停,为每个流出顺序流订阅事件。
- 哪个事件先触发,流程就走那条路,其他订阅被取消。
- 约束:
- 必须有两条或以上流出顺序流。
- 流出顺序流只能连接中间捕获事件,不支持接收任务(Receive Task)。
- 每个中间捕获事件只能有一个入口顺序流。
图形标记
事件网关是一个菱形,里面有个五边形图标。
XML代码
<eventBasedGateway id="exclusiveGateway1" />
代码示例解析
以下是文中给出的事件网关流程示例(客户投诉处理流程):
<signal id="alertSignal" name="alert" flowable:scope="global" /><process id="EventBasedGatwayTest" name="网关-事件网关" isExecutable="true"><startEvent id="ab90dd1d6552e49c09dec232671467890" /><userTask id="a53b48e07e88d4adb8b65bf3ab3460e0a" name="客户投诉" /><sequenceFlow id="a6171b16076dd41b6a67d25fd838218c4" sourceRef="ab90dd1d6552e49c09dec232671467890" targetRef="a53b48e07e88d4adb8b65bf3ab3460e0a" /><eventBasedGateway id="Gateway_0pspvvy" /><sequenceFlow id="Flow_0h5e59j" sourceRef="a53b48e07e88d4adb8b65bf3ab3460e0a" targetRef="Gateway_0pspvvy" /><intermediateCatchEvent id="Event_0f966w5" name="3分钟"><timerEventDefinition><timeDuration>PT2M</timeDuration></timerEventDefinition></intermediateCatchEvent><sequenceFlow id="Flow_0ajw2tf" sourceRef="Gateway_0pspvvy" targetRef="Event_0f966w5" /><intermediateCatchEvent id="Event_0g20b6y" name="信号"><signalEventDefinition signalRef="alertSignal" /></intermediateCatchEvent><sequenceFlow id="Flow_1w1y6zy" sourceRef="Gateway_0pspvvy" targetRef="Event_0g20b6y" /><userTask id="Activity_0aug760" name="二级客服处理" /><sequenceFlow id="Flow_0sqnwot" sourceRef="Event_0f966w5" targetRef="Activity_0aug760" /><userTask id="Activity_1wlis7z" name="一级客户处理" /><sequenceFlow id="Flow_1x3g9hf" sourceRef="Event_0g20b6y" targetRef="Activity_1wlis7z" /><endEvent id="Event_139njtd" /><sequenceFlow id="Flow_143bcf9" sourceRef="Activity_0aug760" targetRef="Event_139njtd" /><sequenceFlow id="Flow_1i2cmpp" sourceRef="Activity_1wlis7z" targetRef="Event_139njtd" /></process>
流程解释
这是一个客户投诉处理流程:
- 开始事件:客户提交投诉(userTask: 客户投诉)。
- 事件网关(Gateway_0pspvvy):流程暂停,订阅两个事件:
- 定时器事件(Event_0f966w5):等待3分钟(PT2M表示2分钟,可能是笔误)。
- 信号事件(Event_0g20b6y):等待“alert”信号。
- 事件触发:
- 如果3分钟内没收到信号,定时器触发,流程走二级客服处理(userTask: 二级客服处理)。
- 如果收到“alert”信号(比如客户再次投诉),信号事件触发,流程走一级客服处理(userTask: 一级客户处理)。
- 结束:处理完成后,流程到达endEvent。
现实场景
想象你在电商平台投诉订单问题:
- 你提交投诉后,系统等待:
- 如果3分钟内没进一步动作(比如你没再次联系客服),投诉交给二级客服处理。
- 如果你很快再次发消息(触发“alert”信号),投诉升级到一级客服处理。
- 哪个事件先发生,流程就走对应的路,其他路取消。
关键点
- 事件网关是事件驱动,不看条件,只看哪个事件先触发。
- 流出顺序流必须连接中间捕获事件,如定时器或信号。
- 触发一个事件后,其他事件订阅取消,流程只走一条路。
总结与对比
网关类型 | 图形标记 | 行为特点 | 使用场景 |
---|---|---|---|
排他网关 | 菱形+“X” | 只能走一条路,根据第一个true条件选择 | 单选决策(如金额判断) |
并行网关 | 菱形+“+” | 所有路并行走,或等待所有路汇合 | 并发任务(如多部门同时审批) |
包容网关 | 菱形+圆圈 | 多条路并行走(条件为true),等待可到达路汇合 | 灵活的多选(如请假天数审批) |
事件网关 | 菱形+五边形 | 等待事件触发,走第一个触发事件的路 | 事件驱动(如超时或信号处理) |
具体实例总结
- 排他网关:费用报销时,金额>10000走总监审批,否则走经理审批。
- 并行网关:产品开发时,前端和后端同时开工,完成后一起进入测试。
- 包容网关:请假时,根据天数可能需要HR实习生、HR助理和直属领导并行审批。
- 事件网关:客户投诉后,等待3分钟或客户再次投诉,决定交给一级还是二级客服。
2.边界事件
在BPMN 2.0中,边界事件是一种特殊的中间事件,附着在某个流程活动(如用户任务、子流程等)的边界上,起到“监控”作用。当某个特定条件或事件发生时,边界事件会被触发,可能中断当前活动并改变流程走向。边界事件是**捕获型(Catching)**事件,等待外部触发(如消息、信号、错误等)。
边界事件分为:
- 中断型:触发后,当前活动被终止,流程走边界事件的后继路径。
- 非中断型:触发后,当前活动继续执行,同时流程走边界事件的后继路径。
Flowable支持的边界事件类型包括:
- 消息边界事件
- 信号边界事件
- 错误边界事件
- 定时器边界事件
- 取消边界事件
- 补偿边界事件
下面逐一解释每种边界事件的定义、用途、代码和示例。
2.1 消息边界事件(Message Boundary Interrupting Event)
定义
消息边界事件附着在某个活动(如用户任务或子流程)上,监听特定消息的到来。当消息到达时,事件触发,流程可能中断当前活动,沿着边界事件的后继路径继续。
- 中断型(cancelActivity="true"):触发后,当前活动被终止。
- 非中断型(cancelActivity="false"):触发后,当前活动继续,同时走边界事件路径。
- 消息可以来自流程中的消息抛出事件(如中间抛出事件或结束事件)或通过API触发。
图形标记
消息边界事件是一个圆圈(中间事件标志),附着在活动边界上,内部有一个信封图标(白色,表示捕获)。中断型用实线,非中断型用虚线。
XML代码
xml
收起自动换行
复制
<message id="theMessage" name="newInvoiceMessage" />
<process id="messageBoundaryInterrputingEventProcess">
<userTask id="usertask1" name="审批任务" />
<boundaryEvent id="messageBoundaryInterrputingEvent" name="Timer" attachedToRef="usertask1" cancelActivity="false">
<messageEventDefinition messageRef="theMessage" />
</boundaryEvent>
</process>
- message:定义消息,id="theMessage",name="newInvoiceMessage"。
- userTask:被监控的活动(usertask1)。
- boundaryEvent:消息边界事件,attachedToRef="usertask1"表示附着在usertask1上,messageRef="theMessage"引用消息,cancelActivity="false"表示非中断型。
触发方式
- 流程内部:通过流程中的消息抛出事件(如messageIntermediateThrowingEvent)或消息结束事件触发。
- API触发:使用Flowable的runtimeService.messageEventReceived方法:
- runtimeService.messageEventReceived("newInvoiceMessage", executionId):发送消息到指定执行流。
- runtimeService.messageEventReceived("newInvoiceMessage", executionId, processVariables):发送消息并更新流程变量。
现实场景
假设你在一个审批流程中:
- 你提交了一个采购申请(userTask: 审批任务),等待经理审批。
- 流程设计了一个消息边界事件,监听“紧急通知”消息。
- 如果审批过程中收到“紧急通知”(比如通过API发送),边界事件触发:
- 如果是中断型,审批任务被取消,流程可能跳转到“紧急处理”任务。
- 如果是非中断型,审批任务继续,同时启动“紧急处理”任务。
代码示例解析
在上述XML中:
- 流程有一个用户任务usertask1(审批任务)。
- 消息边界事件messageBoundaryInterrputingEvent监听newInvoiceMessage消息,附着在usertask1上,非中断型。
- 当收到newInvoiceMessage消息时,流程会沿边界事件的后继顺序流执行,同时usertask1继续运行。
2.2 信号边界事件(Signal Boundary Interrupting Event)
定义
信号边界事件类似于消息边界事件,但监听的是信号,信号是全局性的,可以被流程引擎内多个流程实例捕获。信号可以来自流程中的信号抛出事件或API触发。
- 中断型(cancelActivity="true"):触发后终止当前活动。
- 非中断型(cancelActivity="false"):触发后当前活动继续。
- 信号默认是全局作用域,但可以通过flowable:scope="processInstance"限制为当前流程实例。
图形标记
信号边界事件是一个圆圈,附着在活动边界,内部有三角形信号图标(白色,表示捕获)。中断型用实线,非中断型用虚线。
XML代码
xml
收起自动换行
复制
<signal id="theSignal" name="The Signal" />
<process id="signalBoundaryInterrputingEventProcess">
<userTask id="usertask1" name="测试信号任务" />
<boundaryEvent id="signalBoundaryInterrputingEvent" name="Timer" attachedToRef="usertask1" cancelActivity="false">
<signalEventDefinition signalRef="theSignal" />
</boundaryEvent>
</process>
- signal:定义信号,id="theSignal",name="The Signal"。
- userTask:被监控的任务(usertask1)。
- boundaryEvent:信号边界事件,attachedToRef="usertask1",signalRef="theSignal"引用信号,cancelActivity="false"表示非中断型。
- 限制作用域:可添加flowable:scope="processInstance",如:
xml
收起自动换行
复制<signal id="alertSignal" name="alert" flowable:scope="processInstance" />
触发方式
- 流程内部:通过信号抛出事件(如signalIntermediateThrowingEvent)或信号结束事件触发。
- API触发:
- runtimeService.signalEventReceived("The Signal"):发送信号给所有订阅的处理器。
- runtimeService.signalEventReceived("The Signal", executionId):发送信号给指定执行流。
现实场景
假设你在处理订单:
- 订单处理任务(userTask: 测试信号任务)正在进行。
- 信号边界事件监听“库存不足”信号(The Signal)。
- 如果系统中某处触发了“库存不足”信号(比如仓库系统抛出信号):
- 中断型:订单处理任务被取消,流程跳转到“通知客户”任务。
- 非中断型:订单处理继续,同时启动“通知客户”任务。
- 如果设置了flowable:scope="processInstance",只有当前订单流程会响应信号。
代码示例解析
在上述XML中:
- 信号theSignal定义为全局信号。
- 信号边界事件附着在usertask1上,非中断型。
- 当收到The Signal信号时,流程沿边界事件的后继路径执行,同时usertask1继续运行。
2.3 错误边界事件(Error Boundary Interrupting Event)
定义
错误边界事件用于捕获附着活动抛出的BPMNError异常,通常用于子流程或调用活动。当错误发生时,当前活动被销毁,流程沿错误边界事件的后继路径继续。
- 总是中断型:触发后,当前活动被终止。
- 错误通过errorCode匹配,捕获特定错误或任何错误。
图形标记
错误边界事件是一个圆圈,附着在活动边界,内部有闪电图标(白色,表示捕获),用实线表示。
XML代码
xml
收起自动换行
复制
<error id="theError" errorCode="410" />
<process id="messageBoundaryInterrputingEventProcess">
<userTask id="usertask1" name="处理任务" />
<boundaryEvent id="errorBoundaryInterrputingEvent" name="Timer" attachedToRef="usertask1" cancelActivity="true">
<errorEventDefinition errorRef="theError" />
</boundaryEvent>
</process>
- error:定义错误,id="theError",errorCode="410"。
- userTask:被监控的任务(usertask1)。
- boundaryEvent:错误边界事件,attachedToRef="usertask1",errorRef="theError"引用错误,cancelActivity="true"表示中断型。
触发规则
- 如果errorRef引用了定义的错误(如theError),只捕获匹配errorCode的错误(410)。
- 如果errorRef不匹配任何错误,errorRef被当作errorCode使用。
- 如果未设置errorRef,捕获所有错误。
- 子流程中,错误会向上冒泡,直到找到匹配的错误边界事件。
现实场景
假设你在一个支付流程中:
- 支付任务(userTask: 处理任务)尝试扣款。
- 如果扣款失败,抛出错误(BPMNError with errorCode="410",表示“余额不足”)。
- 错误边界事件捕获错误,终止支付任务,流程跳转到“通知用户余额不足”任务。
代码示例解析
在上述XML中:
- 错误theError定义为errorCode="410"。
- 错误边界事件附着在usertask1上,捕获410错误。
- 当usertask1抛出410错误时,任务被终止,流程沿边界事件路径继续。
2.4 定时器边界事件(Timer Boundary Interrupting Event)
定义
定时器边界事件附着在活动上,设置一个定时器,当定时器触发时,流程沿边界事件的后继路径继续。
- 中断型(cancelActivity="true"):触发后终止当前活动。
- 非中断型(cancelActivity="false"):触发后当前活动继续。
- 定时器需要开启Flowable的作业执行器(configuration.setAsyncExecutorActivate(true))。
图形标记
定时器边界事件是一个圆圈,附着在活动边界,内部有时钟图标(白色,表示捕获)。中断型用实线,非中断型用虚线。
XML代码
xml
收起自动换行
复制
<process id="timerBoundaryEventProcess">
<userTask id="usertask1" name="审批" />
<boundaryEvent id="timerBoundaryEvent" name="Timer" attachedToRef="usertask1" cancelActivity="false">
<timerEventDefinition>
<timeDuration>PT1M</timeDuration>
</timerEventDefinition>
</boundaryEvent>
</process>
- userTask:被监控的任务(usertask1)。
- boundaryEvent:定时器边界事件,attachedToRef="usertask1",timeDuration="PT1M"表示1分钟后触发,cancelActivity="false"表示非中断型。
- 定时器类型:
- timeDate:指定时间触发(如2023-07-14T12:12:14)。
- timeDuration:指定时间段后触发(如PT1M表示1分钟)。
- timeCycle:定期触发(如R2/PT1M表示每1分钟触发2次)。
现实场景
设计一个客户投诉流程:
- 一线客服处理投诉(userTask: 审批),附着一个2小时的定时器边界事件。
- 如果2小时内未完成:
- 中断型:一线客服任务终止,投诉转给二线客服。
- 非中断型:一线客服继续处理,同时通知二线客服介入。
代码示例解析
在上述XML中:
- 定时器边界事件附着在usertask1(审批任务)上,1分钟后触发,非中断型。
- 触发后,流程沿边界事件路径执行,usertask1继续运行。
2.5 取消边界事件(Cancel Boundary Interrupting Event)
定义
取消边界事件只用于事务性子流程,在事务取消时触发。触发后:
- 中断事务子流程内所有活动。
- 执行子流程内已完成活动的补偿边界事件(同步执行)。
- 沿取消边界事件的后继路径继续。
- 总是中断型:触发后事务子流程被终止。
- 每个事务子流程只能有一个取消边界事件。
图形标记
取消边界事件是一个圆圈,附着在事务子流程边界,内部有取消图标(白色,表示捕获),用实线表示。
XML代码
xml
收起自动换行
复制
<process id="cancelBoundaryEventProcess">
<transaction id="transactionSubProcess" name="事务子流程" />
<boundaryEvent id="cancelBoundaryEvent" name="Cancel" attachedToRef="transactionSubProcess">
<cancelEventDefinition />
</boundaryEvent>
</process>
- transaction:事务子流程(transactionSubProcess)。
- boundaryEvent:取消边界事件,attachedToRef="transactionSubProcess",使用cancelEventDefinition。
现实场景
假设你预订酒店(事务子流程):
- 事务子流程包括“扣款”和“预订房间”。
- 如果扣款失败,触发取消边界事件:
- 事务子流程终止。
- 执行补偿(如退款)。
- 流程跳转到“通知用户预订失败”。
代码示例解析
在上述XML中:
- 取消边界事件附着在transactionSubProcess上。
- 当事务取消时,触发事件,终止子流程,执行补偿,沿后继路径继续。
2.6 补偿边界事件(Compensate Boundary Interrupting Event)
定义
补偿边界事件用于处理已完成活动的补偿逻辑,在事务取消或补偿中间事件触发时执行。补偿通过关联的补偿处理器(isForCompensation="true")完成。
- 触发时机:活动完成后,订阅保留,直到流程实例结束或补偿触发。
- 特点:
- 补偿处理器通过关联(association)连接,不是顺序流。
- 补偿处理器没有入口/出口顺序流,仅在补偿时执行。
- 不支持附着在子流程上。
图形标记
补偿边界事件是一个圆圈,附着在活动边界,内部有回退箭头图标(白色,表示捕获),用实线表示。
XML代码
xml
收起自动换行
复制
<process id="compensateBoundaryEventProcess">
<userTask id="usertask1" name="审批" />
<boundaryEvent id="compensateBoundaryEvent1" name="Compensate" attachedToRef="usertask1">
<compensateEventDefinition />
</boundaryEvent>
<serviceTask id="serviceTask1" name="CompensationHandler" isForCompensation="true" flowable:class="**.**.**.****" />
<association id="association1" sourceRef="compensateBoundaryEvent1" targetRef="serviceTask1" associationDirection="None" />
</process>
- userTask:被监控的任务(usertask1)。
- boundaryEvent:补偿边界事件,attachedToRef="usertask1"。
- serviceTask:补偿处理器,isForCompensation="true",通过association连接。
触发方式
- 事务子流程取消,触发补偿。
- 流程中的补偿中间事件触发。
现实场景
假设你预订机票:
- 审批任务(userTask: 审批)完成,记录了预订。
- 如果事务取消(如支付失败),补偿边界事件触发,执行补偿处理器(serviceTask1),取消预订并退款。
代码示例解析
在上述XML中:
- 补偿边界事件附着在usertask1上,连接到补偿处理器serviceTask1。
- 当补偿触发时,执行serviceTask1(如退款逻辑),usertask1已完成,不会被中断。
总结与对比
边界事件类型 | 图形标记 | 触发条件 | 行为 | 使用场景 |
---|---|---|---|---|
消息 | 信封图标 | 消息到达 | 中断/非中断 | 外部消息通知(如紧急处理) |
信号 | 三角形图标 | 信号触发 | 中断/非中断 | 全局事件(如库存不足) |
错误 | 闪电图标 | BPMNError | 中断 | 异常处理(如支付失败) |
定时器 | 时钟图标 | 时间到达 | 中断/非中断 | 超时处理(如投诉超2小时) |
取消 | 取消图标 | 事务取消 | 中断 | 事务子流程取消(如预订失败) |
补偿 | 回退箭头 | 补偿触发 | 非中断 | 补偿逻辑(如退款) |
具体实例总结
- 消息边界事件:采购审批中,收到“紧急通知”消息,跳转到紧急处理(非中断型允许审批继续)。
- 信号边界事件:订单处理中,收到“库存不足”信号,通知客户(全局信号可跨流程)。
- 错误边界事件:支付任务失败,抛出“余额不足”错误,跳转到通知用户。
- 定时器边界事件:投诉处理超2小时,自动转给二线客服。
- 取消边界事件:酒店预订事务取消,触发退款并通知用户。
- 补偿边界事件:机票预订后取消,执行退款逻辑。