(二)BPMN2.0规范介绍——2事件 Events
目录
一、事件定义
1. 定时器事件定义 Timer Event Definitions
(1)定义
(2)timeDate
(3)timeDuration
(4)timeCycle
(5)ISO 8601标准定义
2. 消息事件定义 Message Event Definitions
3. 信号事件定义 Signal Event Definitions
(1)定义
(2)抛出信号事件 Throwing a Signal Event
(3)捕获信号事件 Catching a Signal Event
(4)查询信号事件订阅 Querying for Signal Event subscriptions
(5)信号事件范围 Signal event scope
(6)信号事件示例 Signal Event example(s)
4. 错误事件定义 Error Event Definitions
二、启动事件
1. 空启动事件 None Start Event
2. 定时器启动事件 Timer Start Event
3.消息启动事件 Message Start Event
4. 信号启动事件 Signal Start Event
5. 错误启动事件 Error Start Event
三、结束事件
1. 描述
2. 空结束事件 None End Event
3. 错误结束事件 Error End Event
4. 终止结束事件 Terminate End Event
5. 取消结束事件 Cancel End Event
四、边界事件 Boundary Events
1. 定时器边界事件 Timer Boundary Event
2. 错误边界事件 Error Boundary Event
3. 信号边界事件 Signal Boundary Event
4. 消息边界事件 Message Boundary Event
5. 取消边界事件 Cancel Boundary Even
6. 补偿边界事件 Compensation Boundary Event
五、 捕获中间事件 Intermediate Catching Events
1. 定时器捕获中间事件 Timer Intermediate Catching Event
2. 信号捕获中间事件 Signal Intermediate Catching Event
3. 消息捕获中间事件 Message Intermediate Catching Event
六、抛出中间事件 Intermediate Throwing Event
1. 空抛出中间事件 Intermediate Throwing None Event
2. 信号抛出中间事件 Signal Intermediate Throwing Event
3. 补偿抛出中间事件 Compensation Intermediate Throwing Event
一、事件定义
在流程生命周期的不同阶段发生的事情都被视为一种特定的'事件'。这些'事件'都表现为圆形符号,在BPMN 2.0规范中被明确划分为两大类:捕获型和抛出型两种基本类型。
- 捕获(catching):
当流程运行至此事件时,则会等待直至触发器发出动作。具体类型则由图形标志或XML中的声明来明确说明。捕获事件与抛出事件在视觉表现上存在差异:前者内部无填充(表现为白色)。
- 抛出(throwing):
当流程运行至该事件时, 该系统会自动激活一个对应的触发器. 该触发器的具体类型, 可通过图形符号或XML配置文件来设定. 抛出和捕获事件在显示效果上存在差异, 其核心机制中将相关区域填充为黑色以区分两者.
1. 定时器事件定义 Timer Event Definitions
(1)定义
由预设定时器引发的定时器事件是基于时间安排的任务执行机制。可应用于任务启动阶段(start phase)、任务执行期间(during execution phase)以及任务截止前(prior to completion)的时间点。具体操作流程受到选定工作天历(work schedule calendar)的影响。每个任务都有预设的工作天历配置(default work schedule),此外还可以根据需求为特定任务定制独立的工作天历设置。
<timerEventDefinition activiti:businessCalendarName="custom">
...
</timerEventDefinition>
其中businessCalendarName指向流程引擎配置中的业务日历。如果省略业务日历定义,就使用默认业务日历。
代码解读
定时器定义必须且只能使用下列的一种元素
(2)timeDate
这个方式指定了ISO 8601格式的固定时间。 在这个时间点,会触发触发器。例如:
<timerEventDefinition>
<timeDate>2011‐03‐11T12:13:14</timeDate>
</timerEventDefinition>
代码解读
(3)timeDuration
要在触发之前设置定时器的等待时间,并将其用作timerEventDefinition子元素来配置。遵循ISO 8601时间格式(BPMN 2.0标准所规定)。例如(等待10天):
<timerEventDefinition>
<timeDuration>P10D</timeDuration>
</timerEventDefinition>
代码解读
(4)timeCycle
设置重复周期可应用于定时流程的启动,并可用于向超时用户任务发送多次提醒功能。该元素支持两种不同的实现方式:其中一种格式基于ISO 8601标准设定循环时间间隔;另一种则未明确说明具体实现细节。其中一种格式基于ISO 8601标准设定循环时间间隔;例如(每10小时重复三次):
<timerEventDefinition>
<timeCycle activiti:endDate="2015‐02‐25T16:42:11+00:00">R3/PT10H</timeCycle>
</timerEventDefinition>
代码解读
此外,在配置时间范围时可以选择指定endDate这一字段作为timeCycle的一个可选参数。例如,在时间表达式末尾直接添加即可:R3/PT10H/{EndDate}。当时间段结束时(即到达endDate),应用将会终止运行,并生成其他相关作业任务。如"20150225T16:42:11+00:00"这样的静态字符串也是一个常见的选择方式;另外还可以利用环境变量{EndDate}来实现动态赋值。
<timerEventDefinition>
<timeCycle>R3/PT10H/${EndDate}</timeCycle>
</timerEventDefinition>
代码解读
当两种指定方式被同时采用时,系统将按照属性方式所定义的endDate进行处理。
目前仅有BoundaryTimerEvents和CatchTimerEvent这两种事件类型能够提供EndDate的支持。
此外可以采用cron表达式来设定定时周期。以下示例展示了如何设置一个整点启动且每五分钟触发的触发器:
0 0/5 * * * ?
cron表达式使用规则自行百度
代码解读
重复时间周期更适合采用相对时间概念,在具体实施时需从设定的时间点开始计算(例如任务启动的时间)。与之相比,在 cron 表达式中可直接指定绝对时间值,在这种情况下特别适合用于定时触发 timer start events。
在定时事件配置中可灵活运用 cron 表达式进行参数设置。具体而言,在 cron 表达式的应用中需要特别注意以下几点:首先需要指定合适的字符串格式(如 ISO8601 标准),对于循环事件则应采用 cron 表达式。
<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport">
<timerEventDefinition>
<timeDuration>${duration}</timeDuration>
</timerEventDefinition>
</boundaryEvent>
代码解读
请记住:只有当作业或异步执行机构被启用时(即需要在 activiti.cfg.xml 文件中将jobExecutorActivate或asyncExecutorActivate字段指定为true),定时器才会被触发(因为通常情况下这些功能都是关闭状态)。
(5)ISO 8601标准定义
格式解析
R2/2015-06-04T19:25:16.828696-07:00/P1DT10S
上面的字符串通过"/"分为了三部分即:
重复次数/开始时间/运行间隔
重复次数
R - 将永远重复
R1 - 将重复一次
R231 - 将重复231次。
开始时间
任务第一次运行的时间。如果开始日期时间已经过去,Kala将返回一个错误。
其中"T"用来分割日期和时间,时间后面跟着的"-07:00"表示西七区,注意"-"是连字符,不是减号。
时区默认是0时区,可以用"Z"表示,也可以不写。
对于我国,要使用"+08:00",表示东八区。
上面的字符串表示 2015年6月4日,19点25分16秒828696纳秒,西七区。
运行间隔
运行间隔以"P"开始,和上面一样也是用"T"分割日期和时间,如P1Y2M10DT2H30M15S
P 开始标记
1Y - 一年
2M - 两个月
10D - 十天
T - 时间和日期分的割标记
2H - 两个小时
30M - 三十分钟
15S 十五秒钟
例子,注意如果没有年月日,"T"也不能省略
P1DT1M - 一天一分钟执行一次
P1W - 一周执行一次
PT1H - 一小时执行一次
PT10S - 十秒执行一次
代码解读
2. 消息事件定义 Message Event Definitions
消息事件是指涉及具名消息的特定行为。每个消息都包含一个名称和一个负载。
与信号不同的是, 消息事件仅有一个接收者。
其定义通过 messageEventDefinition 元素来声明, 该元素用于描述这些特殊的行为模式。
messageRef 引用了一个 message 元素, 该message元素需被声明为其父节点为definitions根元素的一个子元素。
以下是具体流程描述: 创建了两个事件实例, 并通过开始事件以及中间捕获机制将它们连接起来。
中间捕获行为会根据指定条件触发相应的处理逻辑。
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="Examples"
xmlns:tns="Examples">
<message id="newInvoice" name="newInvoiceMessage" />
<message id="payment" name="paymentMessage" />
<process id="invoiceProcess">
<startEvent id="messageStart" >
<messageEventDefinition messageRef="newInvoice" />
</startEvent>
...
<intermediateCatchEvent id="paymentEvt" >
<messageEventDefinition messageRef="payment" />
</intermediateCatchEvent>
...
</process>
</definitions>
代码解读
3. 信号事件定义 Signal Event Definitions
(1)定义
基于具名触发源的触发活动即为信号事件。这些活动属于全局广播范畴,并将被分配给所有处于激活状态中的处理器(无论是等待执行的任务实例还是接收触发活动的对象)。
通过signalEventDefinition元素进行定义时需指定一个signal属性来引用该触发源。需要注意的是此signal属性必须被声明为definitions根元素的一个子项。以下示例展示了如何通过中间事件机制抛出并捕获特定类型的触发。
<definitions... >
<!‐‐ 声明信号 ‐‐>
<signal id="alertSignal" name="alert" />
<process id="catchSignal">
<intermediateThrowEvent id="throwSignalEvent" name="Alert">
<!‐‐ 信号事件定义 ‐‐>
<signalEventDefinition signalRef="alertSignal" />
</intermediateThrowEvent>
...
<intermediateCatchEvent id="catchSignalEvent" name="On Alert">
<!‐‐ 信号事件定义 ‐‐>
<signalEventDefinition signalRef="alertSignal" />
</intermediateCatchEvent>
...
</process>
</definitions>
两个 signalEventDefinition 引用同一个 signal 元素。
代码解读
(2)抛出信号事件 Throwing a Signal Event
信号可以通过流程实例采用BPMN结构来释放;同样可以通过编程接口调用Java API来释放信号。在以下位置中提供了org.activiti.engine.RuntimeService类的方法用于借助编程接口调用Java API来释放信号。
该系统支持两种途径实现信号的发布功能:一是通过流程实例采用BPMN结构进行发布;二是可借助现有开发框架直接实现基于JDBC的数据源连接并完成数据提交操作以完成发布任务。
RuntimeService.signalEventReceived(String signalName);
RuntimeService.signalEventReceived(String signalName, String executionId);
代码解读
signalEventReceived(String signalName)与signalEventReceived(String signalName, String executionId)的区别在于:前者仅在全局范围内向所有已订阅的处理器发送信号(即广播),而后者则仅向指定的执行实体发送信号。
(3)捕获信号事件 Catching a Signal Event
通过中间事件的捕捉或作为信号边界的事件来捕获
(4)查询信号事件订阅 Querying for Signal Event subscriptions
可以查询订阅了某一信号事件的所有执行:
List<Execution> executions = runtimeService.createExecutionQuery()
.signalEventSubscriptionName("alert")
.list();
代码解读
可以通过调用signalEventReceived(String signalName, String executionId)方法向一系列任务发送该信号
(5)信号事件范围 Signal event scope
通常情况下,在流程引擎中会进行全局广播。这表示你可以在一个流程实例内触发一个信号事件,并且其他不同流程定义中的各个独立流程实例都会收到这一事件。然而,在某些特定场景下希望仅在一个流程实例内接收该类事件。例如,在使用异步机制时,在两个或多个活动相互排斥的情况下进行操作时就可实现此功能。为了限制信号事件的作用范围(即确定其作用域),应在相应的配置选项中指定scope属性:需要注意的是这一特性并非BPMN 2.0标准支持功能
<signal id="alertSignal" name="alert" activiti:scope="processInstance"/>
代码解读
这个属性的默认值为"global(全局)"。
(6)信号事件示例 Signal Event example(s)
以下阐述了两个不同流程基于信号通信机制的对比分析。首先介绍了一个流程,在保险政策发生更新或变更时触发。随后描述了另一个流程的特点,在经过人工审核确认后,则会触发信号事件,并明确指出相关政策已发生变动:

该事件能够被捕获自所有感兴趣的相关流程实例。以下展示了一个订阅该事件的具体流程示例。

请注意:该事件不会局限于单一的具体流程实例而会向整个系统中的所有流程实例发送信息如果您希望仅向某个特定的流程实例发送该事件则需要自行创建关联并利用相应的查询机制进行定位
4. 错误事件定义 Error Event Definitions
重要提示: BPMN错误与Java异常并非同一类别。实际上,两者在本质上并无交集。BPMN错误事件则是一种用于表示建模业务异常(business exceptions)的机制。相比之下,在Java语言中,则采用各自独特的机制来处理这些异常。
<endEvent id="myErrorEndEvent">
<errorEventDefinition errorRef="myError" />
</endEvent>
代码解读
二、启动事件

1. 空启动事件 None Start Event
- 描述:
“空”启动事件,技术上指的是没有特别指定启动流程实例的触发器。这意味着引擎无法预知何时启动流程实例。空启动事件用于流程实例通过调用下列startProcessInstanceByXXX API方法启动的情况。
- 图标:

- java代码:
> ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX();
>
> 代码解读
- xml表示:
按照空启动事件的定义,在其对应的XML表示中不存在任何子元素(其他类型的启动事件则会有相应的子元素用于说明它们各自的类型)
> <startEvent id="start" name="my start event" />
>
> 代码解读
- 自定义扩展:
formKey: 该标识符用于指代引用表单模板;用户需在启动新流程实例时填写此表单;有关详细信息,请参阅表单章节;例如:
> <startEvent id="request" activiti:formKey="org/activiti/examples/taskforms/request.form" />
>
> 代码解读
- 注意事项:
子流程(subprocess)总是有空启动事件。
2. 定时器启动事件 Timer Start Event
- 描述:
定时触发事件用于在指定时间生成流程实例,在仅需执行单次启动操作或要求在特定时间段内重复触发时均可应用。
- 图标:

- java代码:
> ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX();
>
> 代码解读
- xml表示:
基于定时器启动事件的XML表示格式,则是常规的启动事件声明,并附加定时器定义子元素。请参考定时器定义 了解详细配置方法。
> 1. 示例:流程会启动4次,间隔5分钟,从2011年3月11日,12:13开始
>
> 2. <startEvent id="theStart">
>
> 3. <timerEventDefinition>
>
> 4. <timeCycle>R4/2011‐03‐11T12:13/PT5M</timeCycle>
>
> 5. </timerEventDefinition>
>
> 6. </startEvent>
>
> 7.
>
> 8. 示例:流程会在选定的时间启动一次
>
> 9. <startEvent id="theStart">
>
> 10. <timerEventDefinition>
>
> 11. <timeDate>2011‐03‐11T12:13:14</timeDate>
>
> 12. </timerEventDefinition>
>
> 13. </startEvent>
>
>
>
>
> 代码解读
- 注意事项:
(1)子流程不得包含定时器引发的启动事件。
(2)在同步部署的过程中触发的定时器事件会立即开始计时;无需调用startProcessInstanceByXXX函数(尽管也不排除使用相关功能的可能性),因为调用该函数本身也会触发任务运行。
(3)当发布包含定时器驱动任务的新版本程序时,默认情况下会删除旧版本的任务实例;这是因为通常情况下不再希望旧版本的任务继续执行新的任务初始化操作。
3.消息启动事件 Message Start Event
- 描述:
- 图标:

- java代码:
> 1. 当启动流程实例时,可以使用下列 RuntimeService 中的方法,触发消息启动事件:
>
> 2. ProcessInstance startProcessInstanceByMessage(String messageName);
>
> 3. ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
>
> 4. ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object<processVariables);
>
>
>
>
> 代码解读
messageName 是由 message 元素的 name 属性决定的名字。 message 元素被 messageEventDefinition 的 messageRef 属性引用。当启动流程实例时,请考虑下列因素
(1)只有顶层流程(toplevel process)才支持消息启动事件。嵌入式子流程不支持消息启动事件。
(2)如果一个流程定义中有多个消息启动事件, runtimeService.startProcessInstanceByMessage(…) 允许选择合适的启动事件。
(3)如果一个流程定义中有多个消息启动事件,与一个空启动事件,则 runtimeService.startProcessInstanceByKey(…) 与runtimeService.startProcessInstanceById(…) 会使用空启动事件启动流程实例。(4)如果一个流程定义中有多个消息启动事件,而没有空启动事件,则 runtimeService.startProcessInstanceByKey(…) 与 runtimeService.startProcessInstanceById(…) 会抛出异常。
(5) 如果一个流程定义中只有一个消息启动事件,则 runtimeService.startProcessInstanceByKey(…) 与 runtimeService.startProcessInstanceById(…) 会使用这个消息启动事件启动新流程实例。
(6)如果流程由调用活动(call activity)启动,则消息启动事件只有在下列情况下才被支持 :
- 除了消息启动事件,流程还有唯一的空启动事件
- 或者流程只有唯一的消息启动事件,而没有其他启动事件。
- xml表示:
消息启动事件的XML表示格式基于普通启动事件声明并附加messageEventDef子元素
> 1. <definitions id="definitions"
>
> 2. xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
>
> 3. xmlns:activiti="http://activiti.org/bpmn"
>
> 4. targetNamespace="Examples"
>
> 5. xmlns:tns="Examples">
>
> 6. <message id="newInvoice" name="newInvoiceMessage" />
>
> 7. <process id="invoiceProcess">
>
> 8. <startEvent id="messageStart" >
>
> 9. <messageEventDefinition messageRef="tns:newInvoice" />
>
> 10. </startEvent>
>
> 11. ...
>
> 12. </process>
>
> 13. </definitions>
>
>
>
>
> 代码解读
4. 信号启动事件 Signal Start Event
- 描述:
该信号启动事件采用具名式触发机制。
该信号可由两种途径触发:一种是通过流程实例内部抛出的中间事件(intermediary signal throw event);另一种是通过API调用(如
runtimeService.signalEventReceivedXXX方法)。这两种途径下,默认会触发所有具有相同名称的信号驱动流程定义。
- 图标:

- java代码:
> 1. RuntimeService.signalEventReceived(String signalName);
>
> 2. RuntimeService.signalEventReceived(String signalName, String executionId);
>
>
>
>
> 代码解读
- xml表示:
触发信号启动事件的XML表示格式中,在常规启动事件声明中增加了signalEventDefinition描述。
> 1. <signal id="theSignal" name="The Signal" />
>
> 2. <process id="processWithSignalStart1">
>
> 3. <startEvent id="theStart">
>
> 4. <signalEventDefinition id="theSignalEventDefinition" signalRef="theSignal" />
>
> 5. </startEvent>
>
> 6. <sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />
>
> 7. <userTask id="theTask" name="Task in process A" />
>
> 8. <sequenceFlow id="flow2" sourceRef="theTask" targetRef="theEnd" />
>
> 9. <endEvent id="theEnd" />
>
> 10. </process>
>
>
>
>
> 代码解读
- 注意事项:
在这些情况下,请注意可以选择启动流程的方式:异步或同步。
API所需的signalName由signal元素中的name属性来确定。
信号元素通过signalEventDefinition中的signalRef属性被引用。
5. 错误启动事件 Error Start Event
- 描述:
错误的初始化过程可作为引发特定子流程(Event Sub-Process)的前提条件。
错误初始化过程不具备成为单个实例执行工作流的能力。
此类初始化过程必然导致工作流中断。
错误启动事件标记通常表现为一个未填充的圆圈, 用于指示某个位置存在错误事件标志.
该圆圈未填充, 则表明该位置未捕捉到或未能接收任何异常行为.

- java代码:
> 1. RuntimeService.signalEventReceived(String signalName);
>
> 2. RuntimeService.signalEventReceived(String signalName, String executionId);
>
>
>
>
> 代码解读
- xml表示:
在配置方案中对错误启动事件进行处理时,默认采用普通启动事件的形式,并在此基础上增加errorEventDefinition子元素以明确异常处理逻辑。
> 1. <startEvent id="messageStart" >
>
> 2. <errorEventDefinition errorRef="someError" />
>
> 3. </startEvent>
>
>
>
>
> 代码解读
- 注意事项:
在以下情况下(例如),可以根据需求可以选择启动流程是否为异步或同步。
API需要传递给信号名称(signalName),该名称由signal元素的name属性确定。
信号元素通过signalEventDefinition中的reference属性完成引用。
在以下情况下(例如),可以根据需求可以选择启动流程是否为异步或同步。
API需要传递给信号名称(signalName),该名称由signal元素的name属性确定。
信号元素通过signalEventDefinition中的reference属性完成引用。
三、结束事件
1. 描述
标志该流程(分支)的终结。
结束事件总是触发相应的事件。
意味着当流程达到结束事件时会生成结果。
其类型由嵌入式图标决定。
在XML表示中,类型由子元素声明给出。
标志该流程(分支)的终结。
结束事件总是触发相应的事件。
意味着当流程达到结束事件时会生成结果。
其类型由嵌入式图标决定。
在XML表示中, 类型由子元素声明给出.

2. 空结束事件 None End Event
- 描述:
“空”结束事件,意味着当到达这个事件时,抛出的结果没有特别指定。因此,引擎除了结束当前执行分支之外,不会多做任何事情。
- 图标:
空结束事件,用其中没有图标(没有结果类型)的粗圆圈表示

- java代码:
- xml表示:
在XML中对空事件进行表示时,默认采用普通结束事件的形式而不包含任何直接子实体(其他类型的结束事件则会包含直接子实体以标识其类型)。
> <endEvent id="end" name="my end event" />
>
> 代码解读
- 注意事项:
3. 错误结束事件 Error End Event
- 描述:
当流程达到终止状态时(即出现任务完成失败的情况),系统将终止当前处理路径,并触发异常。此时系统会检查是否有对应的异常类型被捕获(通常称为中间异常类型)。如果没有对应的异常类型被捕获,则会导致异常被触发。
错误结束事件是一个发生的情况。
该情况通常通过一个带有错误图标的标准结束事件(圆形图标)来表示。
该图标的颜色是纯黑色的。
该标识符用于指示异常抛出的状态。

- java代码:
- xml表示:
错误结束事件,表示为结束事件,加上errorEventDefinition子元素:
> 1. <endEvent id="myErrorEndEvent">
>
> 2. <errorEventDefinition errorRef="myError" />
>
> 3. </endEvent>
>
> 4.
>
> 5. errorRef属性可以引用在流程外定义的error元素:
>
> 6.
>
> 7. <error id="myError" errorCode="123" />
>
> 8. ...
>
> 9. <process id="myProcess">
>
> 10. ...
>
> 11.
>
> 12. error的errorCode用于查找匹配的错误捕获边界事件。如果errorRef不匹配任何已定义的error,则该errorRef会用做errorCode的快捷方式。这个快捷方式是Activiti特有的。下面的代码片段在功能上是相同的
>
> 13.
>
> 14. <error id="myError" errorCode="error123" />
>
> 15. ...
>
> 16. <process id="myProcess">
>
> 17. ...
>
> 18. <endEvent id="myErrorEndEvent">
>
> 19. <errorEventDefinition errorRef="myError" />
>
> 20. </endEvent>
>
> 21. ...
>
> 22.
>
> 23. 与下面的功能相同
>
> 24.
>
> 25. <endEvent id="myErrorEndEvent">
>
> 26. <errorEventDefinition errorRef="error123" />
>
> 27. </endEvent>
>
>
>
>
> 代码解读
- 注意事项:
请注意errorRef必须遵从BPMN 2.0概要(schema),且必须是合法的QName。
4. 终止结束事件 Terminate End Event
- 描述:
在触发终止结束事件时,在到达该事件的过程中会导致当前流程实例或子流程被终止。
从理论上讲,在这种情况下系统会首先评估并终止第一个确定的范围(即流程或子流程)。请注意,在BPMN 2.0标准中所述的子过程可能包括嵌入式子过程、调用活动、事件型子过程以及事务型子过程等。
关于这一规则的具体应用,请注意以下几点:当涉及多实例的调用过程或嵌入式子过程时,默认情况下只会触发其中一个实例进行终止操作。
另外一种特殊情况是可以通过设置可选属性terminateAll来实现的功能:当该属性被设置为true时,则无论该终止结束事件位于何处或者是否处于某个特定层次的过程内部(甚至包含嵌套层次的过程),都会导致根层的所有进程都被强制性地停止。
需要注意的是,在某些特殊场景下可能会出现无法完全按照预期执行的情况,请确保相关配置参数设置正确以避免潜在的问题。
(注释:此处为示例中的图标说明)
终止结束事件,用内部有一个全黑圆的标准结束事件(粗圆圈)表示。

- java代码:
- xml表示:
终止-结束事件并归类为结束事件,并添加terminateEventDefinition子元素。
特别注意:terminateAll属性具有可选项性,默认设置为false。
> 1. <endEvent id="myEndEvent >
>
> 2. <terminateEventDefinition activiti:terminateAll="true"></terminateEventDefinition>
>
> 3. </endEvent>
>
>
>
>
> 代码解读
- 注意事项:
5. 取消结束事件 Cancel End Event
- 描述:
在使用bpmn事务子流程时,必须同时应用取消结束事件。
当系统检测到出现取消结束事件时,则会触发抛出取消事件的行为;这一行为必须得到对应的确认和捕捉。
随后系统将执行相应的操作以完成该事务的撤销,并根据预先设定好的补偿机制进行相应的处理。
...
终止事件采用带有取消图标的标准结束事件标记为粗圆圈符号表示其意义

- java代码:
- xml表示:
取消结束事件,表示为结束事件,加上cancelEventDefinition子元素。
> 1. <endEvent id="myCancelEndEvent">
>
> 2. <cancelEventDefinition />
>
> 3. </endEvent>
>
>
>
>
> 代码解读
- 注意事项:
四、边界事件 Boundary Events
边界的捕获型事件被称为依赖于activity的对象;这种类型的对象永远不会抛出异常值。它表示每当activity运行时,在特定条件下会监控触发器以捕捉相关的边界事件。一旦发生被捕获的情况,则会导致activity停止运行,并按照该event的出口顺序继续执行后续操作。所有的边界event都遵循相同的定义方式:
<boundaryEvent id="myBoundaryEvent" attachedToRef="theActivity">
<XXXEventDefinition/>
(如: TimerEventDefinition,ErrorEventDefinition,signalEventDefinition,messageEventDefinition)
</boundaryEvent>
代码解读
由以下元素构成:
(1)带有唯一标识符表示其所属流程范围;
(2)通过attachedToRef属性引用相关活动;
特别注意:边界事件与它们所关联的活动处于同一层级结构中;
这些基于XML的形式中用于描述不同类型的边界事件。查阅相关文档以获取详细信息。

1. 定时器边界事件 Timer Boundary Event
- 描述:
定时器边界事件的行为类似于执行计时任务的过程。当活动依附于边界事件被执行时,则会触发定时器启动流程。在特定条件下(例如预设的时间间隔),定时器会被触发并中断当前活动,在完成当前操作后按照边界事件的顺序依次处理后续活动。
定时器边界事件,用内部有一个定时器图标的标准边界事件(圆圈)表示。

- java代码:
- xml表示:
定时器边界事件与一般边界事件遵循相同规则进行定义。其类型字段对应于timerEventDefinition元素。
> 1. <boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport">
>
> 2. <timerEventDefinition>
>
> 3. <timeDuration>PT4H</timeDuration>
>
> 4. </timerEventDefinition>
>
> 5. </boundaryEvent>
>
>
>
>
> 代码解读
- 注意事项:
2. 错误边界事件 Error Boundary Event
- 描述:
在活动边界的特定部分(称为事件),即错误边界事件中捕获依附于该范围内的异常行为。这种中间现象通常被称为错误边界事件。
为了实现这一目标,在嵌入式系统或者调用活动的过程中建立错误边界事件机制具有重要意义。这是因为嵌套流程会自动分配给每个参与活动一个范围。
通过这种方式,在发生异常时能够更高效地进行定位和处理。
当异常被捕获时,在相关的范围内所有正在进行的操作将被终止。
异常处理流程将按照设置好的出口顺序继续执行直到找到匹配的错误边界事件所定义的范围。
错误边界事件采用带有内部显示一个错误图标的中间事件形式表示。其中显示的错误图标呈白色背景,并用于捕获异常信息。

- java代码:
- xml表示:
错误边界事件与标准边界事件一样定义:
> 1. <boundaryEvent id="catchError" attachedToRef="mySubProcess">
>
> 2. <errorEventDefinition errorRef="myError"/>
>
> 3. </boundaryEvent>
>
>
>
>
> 代码解读
在边界事件中,errorRef引用一个流程元素外定义的错误:
> 1. <error id="myError" errorCode="123" />
>
> 2. ...
>
> 3. <process id="myProcess">
>
> 4. ...
>
>
>
>
> 代码解读
errorCode用于匹配捕获的错误:
(1)如果省略了errorRef,错误边界事件会捕获所有错误事件,无论error的errorCode是什么。
(2)如果提供了errorRef,并且其引用了存在的error,则边界事件只会捕获相同错误代码的错误。
(3)如果提供了errorRef,但BPMN 2.0文件中没有定义error,则errorRef会用作errorCode(与错误结束事件类似)。
- 示例:
以下示例流程说明了如何利用错误终止事件。当'Review profitability'任务完成后发现信息不足以满足要求时, 将触发异常。如果该错误被子流程边界捕获,则该子 workflow 的所有正在进行中的 activity 将被终止(即便未完成 'Review customer rating' 的 task)。此操作后将创建 'Provide additional details' 用户 task

3. 信号边界事件 Signal Boundary Event
- 描述:
依附在活动边界上的信号捕获中间(事件),或简称信号边界事件,捕获与其信号定义具有相同信号名的信号。
请注意:与其他事件例如错误边界事件不同的是,信号边界事件不只是捕获其所依附范围抛出的信号。信号边界事件为全局范围(广播)的,意味着信号可以从任何地方抛出,甚至是不同的流程实例。
请注意:与其他事件如错误事件不同,信号在被捕获后不会被消耗。如果有两个激活的信号边界事件,捕获相同的信号事件,则两个边界事件都会被触发,哪怕它们不在同一个流程实例里。
- 图标:
以特定符号标记的信号边界事件通常使用带有内部信号标志的标准中间事件形式来表示。这些标准中间事件由两层圆圈构成,并且标志采用白色设计以指示捕获操作。

- java代码:
- xml表示:
信号边界事件与标准边界事件一样定义:
> 1. <boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true">
>
> 2. <signalEventDefinition signalRef="alertSignal"/>
>
> 3. </boundaryEvent>
>
>
>
>
> 代码解读
4. 消息边界事件 Message Boundary Event
- 描述:
位于活动边界的中间环节的消息捕获点(也称为消息边界事件),用于捕获与其消息定义具有相同名称的消息。
- 图标:
消息边界的事件通常通过包含一个消息图标的典型中间节点来表示。其中一种典型的中间事件是由两个同心圆圈组成的结构,并在其内部放置特定的信息标记。这种结构被称为消息边界事件,并且其信号标志呈白色,在信息处理系统中被用来标识信息捕获的位置。

需特别注意消息边界事件不仅包括中断型(右手边),也包括非中断型(左手边)。
- xml表示:
消息边界事件与标准边界事件一样定义:
> 1. <boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true">
>
> 2. <messageEventDefinition messageRef="newCustomerMessage"/>
>
> 3. </boundaryEvent>
>
>
>
>
> 代码解读
5. 取消边界事件 Cancel Boundary Even
- 描述:
在事务子流程边界的依附物——即所谓的取消捕获中间(event),亦即简称为取消边界event——发生的时候,在发生当中的时刻会发生停顿以处理当前操作序列中的所有活动任务。随后将会启动包含在当前操作序列中的所有有效compensation boundary event(compensation boundary event)。这些补偿过程将会同步进行,在结束当前操作序列之前都会有对应的compensation boundary event等待其完成任务之后再行继续下一个阶段的操作序列处理步骤。一旦所有的compensation boundary event都已经成功地完成了其相应的操作任务之后,则将会按照预先设定好的出口顺序流路径离开相应的操作序列并进入到下一层的操作序列处理环节中去运行。
- 图标:
消除了边界的事件采用带有内部取消图标的中间类型事件(由两个同心圆圈构成)来表示。其中,白色且未填充的取消图标用于表示捕获的意义。

- java代码:
- xml表示:
取消边界事件与标准边界事件一样定义:
> 1. <boundaryEvent id="boundary" attachedToRef="transaction" >
>
> 2. <cancelEventDefinition />
>
> 3. </boundaryEvent>
>
>
>
>
> 代码解读
因为取消边界事件总是中断型的,因此不需要 cancelActivity 属性。
- 注意:
(1)仅能接收单一的取消边界事件。
(2)当嵌套的子流程存在时,请注意仅当所有嵌套的子流程均完成成功后才会有补偿发生。
(3)当将取消边界事件配置于一个多实例特性设置的事务子流程时,在任何一个实例发生取消行为后, 该取消边界事件将自动终止所有其他相关实例.
6. 补偿边界事件 Compensation Boundary Event
- 描述:
在事务子流程的边缘处附着的取消捕获中间(即取消捕获事件),简称取消边缘事件,在事务处理被撤销时会被激活。当取消边缘事件被激活时,在当前范围内的所有活动执行会被强行中断。
接下来将开始启动所有有效的补偿边缘事件(compensation boundary events)。这些补偿边缘事件会与依附于活动边界的捕获中间相互作用。
需要注意的是:这些补偿边缘事件必须通过直接关联的方式引用单一的补偿处理器。
与其他类型的边界事件不同:
当其他类型的边界事件(如信号边沿)依附于某个活动而被激活时,在该活动完成之后会被解除;而不会创建相应的订阅。
补偿边沿不同于其他类型边沿的是:其依附的活动成功完成后会自动触发相应的补救措施。
如果这些补救边沿依附于具有多实例特性的活动,则会对每一个实例分别创建补救订阅。
只有在流程实例完成时才会终止补救订阅。
补偿边界事件可采用带有补偿图标的典型中间事件(由两个圆圈构成)进行表示。其中 Compensation Icon 采用无色(非填充)设计以体现捕获属性。此外,在处理这类事件时通常会建立单向连接以关联相应的Compensation Processor 如下所示:

- java代码:
- xml表示:
补偿边界事件与标准边界事件一样定义:
> 1. <boundaryEvent id="compensateBookHotelEvt" attachedToRef="bookHotel" >
>
> 2. <compensateEventDefinition />
>
> 3. </boundaryEvent>
>
> 4. <association associationDirection="One" id="a1" sourceRef="compensateBookHotelEvt" targetRef="undoBookHotel" />
>
> 5. <serviceTask id="undoBookHotel" isForCompensation="true" activiti:class="..." />
>
>
>
>
> 代码解读
补偿边界事件在活动完成后才激活,因此不支持 cancelActivity 属性。
- 注意:
(1)嵌入式子流程不支持补偿边界事件。
五、 捕获中间事件 Intermediate Catching Events
所有的捕获中间事件都使用相同方式定义:
<intermediateCatchEvent id="myIntermediateCatchEvent" >
<XXXEventDefinition/>
</intermediateCatchEvent>
代码解读
捕获中间事件由以下元素构成
(1)包括流程范围内的唯一标识符
(2)对应特定中间捕获事件类型的XXXEventDefinition格式的XML子元素(例如TimerEventDefinition等)。进一步查阅具体中间捕获事件类型以获取详细信息
1. 定时器捕获中间事件 Timer Intermediate Catching Event
- 描述:
定时器捕捉中间事件的行为类似于一种计时机制。每当发生捕获事件活动(即catching event activity),系统会开始运行定时器;一旦触发(通常在预设的时间间隔之后),系统会按照...的出口顺序继续执行相应的流程。
- 图标:
定时器中间事件,用内部有定时器图标的中间捕获事件表示

- java代码:
- xml表示:
定时器中间事件应遵循与捕获中间事件相同的定义原则。对于指定类型的子元素来说,应将其设置为timerEventDefinition元素:
> 1. <intermediateCatchEvent id="timer">
>
> 2. <timerEventDefinition>
>
> 3. <timeDuration>PT5M</timeDuration>
>
> 4. </timerEventDefinition>
>
> 5. </intermediateCatchEvent>
>
>
>
>
> 代码解读
查看定时器事件定义了解详细配置。
- 注意:
2. 信号捕获中间事件 Signal Intermediate Catching Event
- 描述:
捕捉中间事件(记为S),该中间事件与所引用的信号定义具有相同名称。
请注意:与错误等其他类型的事件不同,在被捕获之后不会被消耗。
如果有多个状态转换器(记为A和B)均捕获同一状态S,则A和B都会触发该状态S作为输入。
即使它们不属于同一个流程实例。
图标:
捕获中间事件采用内部带有信号图标的规范中间事件(由两层圆圈构成),其中信号图标为白色无填充区域以表示捕获行为。

- java代码:
- xml表示:
采用相同的方式定义信号类中间事件与捕获类中间事件。通过设置具体类型为signalEventDefinition元素来实现。
> 1. <intermediateCatchEvent id="signal">
>
> 2. <signalEventDefinition signalRef="newCustomerSignal" />
>
> 3. </intermediateCatchEvent>
>
>
>
>
> 代码解读
- 注意:
3. 消息捕获中间事件 Message Intermediate Catching Event
- 描述:
消息捕获中间事件,捕获特定名字的消息。
- 图标:
该系统采用带有白色未填充两层圆圈的标准中间事件来表示消息捕获过程。这种设计选择能够清晰传达捕获操作的关键信息,并通过视觉编码帮助操作者快速识别相关事件的发生位置和时间点。

- java代码:
- xml表示:
消息中间事件与捕捉中间事件相同定义。将指定类型作为messageEventDefinition元素。
> 1. <intermediateCatchEvent id="message">
>
> 2. <messageEventDefinition signalRef="newCustomerMessage" />
>
> 3. </intermediateCatchEvent>
>
>
>
>
> 代码解读
- 注意:
六、抛出中间事件 Intermediate Throwing Event
所有的抛出中间事件都使用相同方式定义:
<intermediateThrowEvent id="myIntermediateThrowEvent" >
<XXXEventDefinition/>
</intermediateThrowEvent>
代码解读
发生中间事件的过程可由以下(元素)构成
其中第(1)项为唯一标识符(流程范围)
这些基于XXXEventDefinition格式的XML子元素用于定义特定的抛出中间事件类型。通过查询特定中间抛出事件类型可获得详细信息。
1. 空抛出中间事件 Intermediate Throwing None Event
- 描述:
下面的流程图示例展示了空中间事件的简单情况,并用于指示流程已达到特定的状态

一般情况下,在空中间事件中安装一个执行监听器(execution listener)后,则这些事件可以很好地作为监视关键绩效指标(KPI)的关键钩子。

- java代码:
- xml表示:
> 1. <intermediateThrowEvent id="noneEvent">
>
> 2. <extensionElements>
>
> 3. <activiti:executionListener
>
> 4. class="org.activiti.engine.test.bpmn.event.IntermediateNoneEventTest$MyExecutionListener"
>
> 5. event="start" />
>
> 6. </extensionElements>
>
> 7. </intermediateThrowEvent>
>
>
>
>
> 代码解读
你可以添加一些代码来将部分事件提交给你的BAM(业务活动监控)工具或DWH(数据仓库)。引擎本身不会对事件进行任何操作,仅仅是作为中间环节处理。
2. 信号抛出中间事件 Signal Intermediate Throwing Event
- 描述:
触发已定义信号的事件会被抛出。
在Activiti中,当发生了一个事件时,默认情况下该事件会向所有相关的处理器发送触发信息。
(1)默认配置下采用同步机制进行触发传输。这意味着当一个抛出(信号)流程实例被触发后会等待直至所有捕获(信号)流程实例都收到该通知;只有当所有捕获流程实例在同一事务中同时收到通知时才会继续执行;如果其中一个捕获流程实例因技术错误而产生异常,则会导致相关联的所有关联实例也会受到影响而失败。
(2)为了实现高效的触发管理,在发生异常情况时系统将采用异步机制进行触发传输操作;具体来说每当抛出一个异常时 JobExecutor会为每个激活的处理器存储并发送一个异步通知消息
(asynchronous notification message 或者 Job)。这些异步消息将在后续处理过程中逐步被分配给相应的处理节点完成触发操作。
- 图标:
消息被抛出中间事件时,则采用带有信号图标的中间事件来表示。(注:两层圆圈构成的标准中间事件)该信号图标呈黑色并已填充色,用于指示抛出的意义。

- java代码:
- xml表示:
信号中间事件与抛出中间事件相同地进行定义。将指定类型的子元素设为signalEventDefinition元素。
> 1. <intermediateThrowEvent id="signal">
>
> 2. <signalEventDefinition signalRef="newCustomerSignal" />
>
> 3. </intermediateThrowEvent>
>
>
>
>
> 代码解读
异步信号事件像这样定义:
> 1. <intermediateThrowEvent id="signal">
>
> 2. <signalEventDefinition signalRef="newCustomerSignal" activiti:async="true" />
>
> 3. </intermediateThrowEvent>
>
>
>
>
> 代码解读
- 注意:
3. 补偿抛出中间事件 Compensation Intermediate Throwing Event
- 描述:
补偿抛出中间事件,可用于触发补偿。
触发补偿:补偿既可以为设计的活动触发,也可以为补偿事件所在的范围触发。补偿由活动所关联的补偿处理器执行。(1)抛出补偿时,活动关联的补偿处理器执行的次数,与活动成功完成的次数相同。
(2)如果为当前范围抛出了补偿,则当前范围中所有的活动都会被补偿,包括并行分支上的活动。
(3)补偿分层触发:如果将要被补偿的活动是一个子流程,则该子流程中所有的活动都会触发补偿。如果该子流程有嵌套的活动,则会递归地抛出补偿。然而,补偿不会传播至流程的上层:如果子流程中触发了补偿,该补偿不会传播至子流程范围外的活动。BPMN规范指出,补偿为“与子流程在相同级别”的活动触发。
(4)在Activiti中,补偿按照执行的相反顺序运行。这意味着最后完成的活动会第一个补偿,等等。
(5)补偿抛出中间事件,可用于补偿已经成功完成的事务子流程。请注意:如果抛出补偿的范围中有一个子流程,而该子流程包含有关联了补偿处理器的活动,则当抛出补偿时,只有当该子流程成功完成的情况,补偿才会传播至该子流程。如果子流程内嵌套的部分活动已经完成,并附加了补偿处理器,则如果包含这些活动的子流程还没有完成,这 些补偿处理器不会执行。参考下面的例子:

在这个流程中,有两个并行的执行。一个执行嵌入子流程,另一个执行“charge credit card(信用卡付款)”活动。假定两个执行都已开始,且第一个并行执行正等待用户完成“review bookings(检查预定)”任务。第二个执行进行了“charge credit card(信用卡付款)”活动的操作,抛出了一个错误,导致“cancel reservations(取消预订)”事件触发补偿。这时并行子流程还未完成,意味着补偿不会传播至该子流程,因此不会执行“cancel hotel reservation(取消酒店预订)”补偿处理器。而如果“cancel reservations(取消预订)”运行前,这个用户任务(因此该嵌入式子流程也)已经完成,则补偿会传播至该嵌入式子流程。
流程变量:当补偿嵌入式子流程时,用于执行补偿处理器的执行,可以以变量在子流程完成时所处的状态,访问子流程的局部流程变量。为了实现这一点,会为范围执行(为执行子流程所创建的执行)所关联的流程变量,进行快照。意味着:
(1)子流程范围内创建的并行执行所添加的变量,补偿执行器无法访问。
(2)上层的执行关联的流程变量(例如流程实例的执行关联的流程变量),不在该快照中:补偿处理器(本就)可以以其在抛出补偿时所处的状态,访问这些流程变量。
(3)只会为嵌入式子流程,而不会为其他活动,进行变量快照。目前的限制:
(1)目前不支持 waitForCompletion="false" 。当补偿抛出中间事件触发补偿时,只有在补偿成功完成时,才会离开该事件。
(2)补偿现在由并行执行来运行。该并行执行按照补偿活动完成的逆序启动。Activiti的后续版本可能会添加选项,使补偿可以按(活动完成的)顺序运行。
(3)补偿不会传播至调用活动(call activity)生成的子流程。
- 图标:
为中间事件的抛出提供补偿,请使用带有填充黑色两层圆圈的标准中间事件作为指示符号。该补分为黑色填充状态,并象征着原始事件被释放。

- java代码:
- xml表示:
补偿中间事件与抛出中间事件等同于定义方式的一致性要求;将指定类型中的子项归类为compensateEventDefinition元素。
> 1. <intermediateThrowEvent id="throwCompensation">
>
> 2. <compensateEventDefinition />
>
> 3. </intermediateThrowEvent>
>
>
>
>
> 代码解读
另外, activityRef 可选项可用于为指定的范围/活动触发补偿:
> 1. <intermediateThrowEvent id="throwCompensation">
>
> 2. <compensateEventDefinition activityRef="bookHotel" />
>
> 3. </intermediateThrowEvent>
>
>
>
>
> 代码解读
- 注意:
