activiti中常见的事件按事件可以出现的位置可以分为 开始事件、结束事件、边界事件、中间事件。
按事件的类型分可以分为信号事件、消息事件、error事件,定时器事件
按照事件的特性可以分为Catching事件和Throwing事件,Catching会一直等待被触发,Throwing事件会自动触发并反馈结果,全部的开始事件都是Catching事件,全部的结束事件都是Throwing事件,结束事件会自动执行并返回结果。
一、开始事件
1.1 无指定开始事件
最常用的流程开始事件,有这种开始事件的流程需要使用RutimeService来启动。
1.2 定时器开始事件
把定时器事件放在开始的位置,用于定时的启动流程,有这种开始事件的流程不需要用api来启动。
<startEvent id="sid-EF961064-FBCE-4FDF-B855-DFDC50A70E06">
<timerEventDefinition></timerEventDefinition>
</startEvent>
如上,定时器开始事件像这样定义,触发的时间需要在timerEventDefinition中加入子元素来指定,
timeDate: 指定一个定时器触发的时间,如2023-06-01T06:00:00
timeDuration: 指定定时器被激活后多久会执行,假如当前时刻被激活,设置该值为PT5M,表示5分钟后会执行。
timeCycle: 指定定时器重复执行的间隔,设置这个值后定时器会每隔一段时间就重复执行一次,
该配置支持cron表达式
上边这个流程使用了定时器开始事件,并指定了timeDate,部署此流程文件后到达指定时间时就会自动启动此流程。
<startEvent id="sid-EF961064-FBCE-4FDF-B855-DFDC50A70E06">
<timerEventDefinition>
<timeDate>2023-06-18T21:09:00</timeDate>
</timerEventDefinition>
</startEvent>
1.3 消息开始事件
为开始事件加入消息事件的定义,这种流程需要使用RuntimeService.startProcessByMessage方法启动。
// 注意入参要使用messageName
ProcessInstance startProcessInstanceByMessage(String messageName);
需要在流程文件中先定义message,然后在消息事件定义中引用定义的消息
上边这个流程中使用了消息开始事件,部分流程文件如下,注意一开始先定义了消息
<message id="myMessage" name="myMessage"></message>
<process id="process" isExecutable="true">
<startEvent id="sid-4C60A445-5925-40CE-9AFB-E72E7A341E82">
<messageEventDefinition messageRef="myMessage"></messageEventDefinition>
</startEvent>
<userTask id="userTask1" name="message start task"></userTask>
<sequenceFlow id="sid-0F009245-57A2-4F15-9B79-F86521C03A4E" sourceRef="sid-4C60A445-5925-40CE-9AFB-E72E7A341E82" targetRef="userTask1"></sequenceFlow>
<endEvent id="sid-A5DE705E-23BF-4D29-A5A1-5BF93F0341F2"></endEvent>
<sequenceFlow id="sid-B4BEA749-046C-4AA6-9413-416881C52E80" sourceRef="userTask1" targetRef="sid-A5DE705E-23BF-4D29-A5A1-5BF93F0341F2"></sequenceFlow>
</process>
1.4 错误开始事件
错误开始事件只能在事件子流程中使用。
上边这个流程图,上半部分是一个主流程,它有一个serviceTask关联了一个java类,在java类中会抛出BpmnError。下半部分是一个事件子流程,它有个错误开始事件,当捕获到主流程抛出的错误时就会启动子流程。
service task关联的java类
public class ThrowErrorServiceTask implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception {
System.out.println("抛出error");
//构造方法的参数是errorCode
throw new BpmnError("testError");
}
}
整个流程的流程文件
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<!-- error定义 -->
<error id="testError" errorCode="testError"></error>
<process id="errorStartTest" name="errorStartTest" isExecutable="true">
<startEvent id="sid-F856CED3-6AE3-4F88-BC43-0E9DAB2B016B"></startEvent>
<serviceTask id="sid-AC5D1738-EF21-4126-B92E-1CA34A9E62B0" name="throw error" activiti:class="com.lyy.serviceTask.ThrowErrorServiceTask"></serviceTask>
<sequenceFlow id="sid-24A60E23-D939-44BF-8433-1C8DACAD3197" sourceRef="sid-F856CED3-6AE3-4F88-BC43-0E9DAB2B016B" targetRef="sid-AC5D1738-EF21-4126-B92E-1CA34A9E62B0"></sequenceFlow>
<endEvent id="sid-57EA43F4-D87D-48E5-8240-6B729F03DDF1"></endEvent>
<sequenceFlow id="sid-07A2F280-19B5-43D4-8319-015A9C806040" sourceRef="sid-AC5D1738-EF21-4126-B92E-1CA34A9E62B0" targetRef="sid-57EA43F4-D87D-48E5-8240-6B729F03DDF1"></sequenceFlow>
<subProcess id="errorDealSubProcess" name="subProcess" triggeredByEvent="true">
<startEvent id="sid-D66367D7-6F71-480B-9E18-85758C3D1166">
<!-- 错误事件定义,引用testError这个error -->
<errorEventDefinition errorRef="testError"></errorEventDefinition>
</startEvent>
<userTask id="sid-B3A07EC3-1F53-4D8B-AEB6-CD859FFD9A6E" name="error task" activiti:assignee="kermit"></userTask>
<endEvent id="sid-ACF84D26-3842-434B-8E32-641F248864BC"></endEvent>
<sequenceFlow id="sid-5EC3D575-386D-4505-B383-AF4831F752E5" sourceRef="sid-D66367D7-6F71-480B-9E18-85758C3D1166" targetRef="sid-B3A07EC3-1F53-4D8B-AEB6-CD859FFD9A6E"></sequenceFlow>
<sequenceFlow id="sid-B6D6FB29-5DF6-4585-A588-5C9535F39945" sourceRef="sid-B3A07EC3-1F53-4D8B-AEB6-CD859FFD9A6E" targetRef="sid-ACF84D26-3842-434B-8E32-641F248864BC"></sequenceFlow>
</subProcess>
</process>
</definitions>
在serviceTask中抛出bpmn异常就会触发事件子流程中的错误开始事件。如果指定了errorRef就只会监听对应的errorCode,如果不指定errorRef所有的BpmnError都会触发此错误开始事件。
注意error只在当前流程的范围内有效,流程A里边抛出的error不会被流程B捕获到。
二、结束事件
结束事件都是抛出事件,这些事件会自动执行并反馈结果。使用endEvent元素定义结束事件。
2.1 无指定结束事件
流程在结束时不会进行任何额外的操作。
2.2 错误结束事件
当执行流到达错误结束事件时会结束该执行流并且抛出错误,该错误可以被"错误边界事件"捕获,如果没有定义任何的错误边界事件当前这个错误结束事件就会被当作无指定错误事件执行,因此错误结束事件一般在子流程中使用。
上边这个流程启动后会到达一个嵌套子流程,在子流程内部sub task任务完成后经过排他网关后有两个分支,网关出口的两条线上添加了 ${days<5} 和${days>=5}
的条件,当流程变量days<5时子流程正常结束,主流程到达endTask,当days>=5时子流程到达错误结束事件抛出错误,这个流程中定义抛出的errorRef是subError,
然后子流程边界上定义了错误边界事件,引用的也是subError,所以会捕获抛出的异常然后流程到达error task
在启动流程时需要传入流程变量
RuntimeService runtimeService = applicationContext.getBean(RuntimeService.class);
Map<String,Object> map = new HashMap<String, Object>();
map.put("days",4);
runtimeService.startProcessInstanceByKey("errorEndEvent",map);
runtimeService.deleteProcessInstance("91574","test");
完整的流程文件
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<!-- 错误定义 -->
<error id="subError" errorCode="subError"></error>
<process id="errorEndEvent" isExecutable="true">
<startEvent id="sid-B5DB263B-B85B-468E-AD7D-69931BF84027"></startEvent>
<subProcess id="sid-8FE783C6-0078-4451-80F0-F0A5ECB9B0E1" name="subProcess">
<startEvent id="sid-EE6B144F-A942-4E8C-AACD-B306F77CAEF4"></startEvent>
<userTask id="subTask" name="sub task"></userTask>
<exclusiveGateway id="sid-0CD31408-A9AA-4A65-B5D1-7B56B7EB492D"></exclusiveGateway>
<endEvent id="sid-39D597D9-1356-4A06-BDE1-612E623CD5CD"></endEvent>
<!-- 错误结束事件 -->
<endEvent id="sid-A70F88EC-FA1C-4216-8332-9C015735C20C">
<errorEventDefinition errorRef="subError"></errorEventDefinition>
</endEvent>
<sequenceFlow id="sid-A83781E7-B0EA-4428-A4E7-A43E1A346D5B" sourceRef="sid-EE6B144F-A942-4E8C-AACD-B306F77CAEF4" targetRef="subTask"></sequenceFlow>
<sequenceFlow id="sid-130DE08E-8B56-4A09-8001-8703C38BF3F7" sourceRef="subTask" targetRef="sid-0CD31408-A9AA-4A65-B5D1-7B56B7EB492D"></sequenceFlow>
<sequenceFlow id="sid-D8DD81EA-7C81-44E1-A55F-780460AFBAEB" sourceRef="sid-0CD31408-A9AA-4A65-B5D1-7B56B7EB492D" targetRef="sid-39D597D9-1356-4A06-BDE1-612E623CD5CD">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${days<5}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="sid-7A76813A-7811-4285-BD7C-E21D04B61157" sourceRef="sid-0CD31408-A9AA-4A65-B5D1-7B56B7EB492D" targetRef="sid-A70F88EC-FA1C-4216-8332-9C015735C20C">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${days>=5}]]></conditionExpression>
</sequenceFlow>
</subProcess>
<userTask id="endTask" name="endTask"></userTask>
<sequenceFlow id="sid-4F53CCE3-D1CE-49CA-88D8-7F8765F8689E" sourceRef="sid-8FE783C6-0078-4451-80F0-F0A5ECB9B0E1" targetRef="endTask"></sequenceFlow>
<endEvent id="sid-8CE1BAED-26F0-45C1-8F6A-312630401E25"></endEvent>
<sequenceFlow id="sid-6E81D5EC-E7EF-4812-8F81-571BB0EAD2F4" sourceRef="endTask" targetRef="sid-8CE1BAED-26F0-45C1-8F6A-312630401E25"></sequenceFlow>
<!-- 错误边界事件 -->
<boundaryEvent id="sid-627F3E39-464C-4AD1-B269-F5B588C53894" attachedToRef="sid-8FE783C6-0078-4451-80F0-F0A5ECB9B0E1">
<errorEventDefinition errorRef="subError"></errorEventDefinition>
</boundaryEvent>
<userTask id="errorTask" name="error task"></userTask>
<sequenceFlow id="sid-9FF79957-5F09-48F1-9C15-D461FC8F8593" sourceRef="sid-627F3E39-464C-4AD1-B269-F5B588C53894" targetRef="errorTask"></sequenceFlow>
<endEvent id="sid-672DDBF7-8025-4EEF-B15B-1BE9401C6929"></endEvent>
<sequenceFlow id="sid-E6E71E95-DB6F-4ED4-9130-2FABC5E6F609" sourceRef="errorTask" targetRef="sid-672DDBF7-8025-4EEF-B15B-1BE9401C6929"></sequenceFlow>
<sequenceFlow id="sid-8C67E741-D0F0-42FE-84FB-9D5298ED9376" sourceRef="sid-B5DB263B-B85B-468E-AD7D-69931BF84027" targetRef="sid-8FE783C6-0078-4451-80F0-F0A5ECB9B0E1"></sequenceFlow>
</process>
</definitions>
2.3 取消结束事件和取消边界事件
取消结束事件只能在事务子流程中使用,一般会和取消边界事件配合使用,取消结束事件会触发依附在事务子流程边界上的取消边界事件。取消边界事件的触发会触发补偿机制。
当取消边界事件被触发时会将当前的流程中断,然后同步的执行补偿机制。取消边界事件在离开事务子流程前会一直等待所有补偿任务的结束,当补偿任务结束后执行流会从取消边界事件离开子流程。
下面有一个汇款流程,汇款流程作为一个事务子流程在主流程中使用,当汇款完成后需要用户进行最终确认,如果用户确认则正常结束流程,否则触发取消结束事件并进行补偿操作。
其中的汇款操作,取消汇款,接收取消都是简单的打印一句话
取消结束事件就会触发取消汇款这个补偿,补偿完成后会到达取消边界事件
完整的流程图
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="cancelEndEvent1" isExecutable="true">
<transaction id="eventSub" name="subProcess">
<startEvent id="sid-8BC8D0D3-4919-4C4B-92D1-89482A047D6A"></startEvent>
<serviceTask id="huiKuan" name="汇款操作222" activiti:class="com.lyy.serviceTask.HuiKuanService"></serviceTask>
<exclusiveGateway id="sid-056E07FA-4CEE-4CC9-ACD4-E3716FAEF48C"></exclusiveGateway>
<endEvent id="sid-22A5F886-CDBD-47F0-B17A-A1A6E236E63A"></endEvent>
<endEvent id="sid-B82F2759-AF61-46DB-98DF-9CD1EC0F678E">
<cancelEventDefinition></cancelEventDefinition>
</endEvent>
<boundaryEvent id="sid-7003DABD-72C5-4570-9F28-717590290F0F" attachedToRef="huiKuan" cancelActivity="true">
<compensateEventDefinition></compensateEventDefinition>
</boundaryEvent>
<serviceTask id="cancelHuiKuan" name="取消汇款" activiti:class="com.lyy.serviceTask.CancelHuiKuan" isForCompensation="true"></serviceTask>
<userTask id="confirm" name="确认汇款"></userTask>
<sequenceFlow id="sid-2298D967-FD3F-4F98-B959-721F8A1643DC" sourceRef="sid-8BC8D0D3-4919-4C4B-92D1-89482A047D6A" targetRef="huiKuan"></sequenceFlow>
<sequenceFlow id="sid-5376EBB8-A8DC-4561-960C-AF61F6ED09F2" sourceRef="huiKuan" targetRef="confirm"></sequenceFlow>
<sequenceFlow id="sid-258E4C3C-73E0-4EFA-8A69-01E40F4E36FF" sourceRef="confirm" targetRef="sid-056E07FA-4CEE-4CC9-ACD4-E3716FAEF48C"></sequenceFlow>
<sequenceFlow id="sid-91FB9340-201D-4324-90FB-A11970667985" sourceRef="sid-056E07FA-4CEE-4CC9-ACD4-E3716FAEF48C" targetRef="sid-B82F2759-AF61-46DB-98DF-9CD1EC0F678E">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${flag==false}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="sid-F42022BA-F52B-44A5-8934-B6C1697BB2F4" sourceRef="sid-056E07FA-4CEE-4CC9-ACD4-E3716FAEF48C" targetRef="sid-22A5F886-CDBD-47F0-B17A-A1A6E236E63A">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${flag==true}]]></conditionExpression>
</sequenceFlow>
</transaction>
<startEvent id="sid-FBF27FA9-358F-4921-BE80-4A1C41B3E2E7"></startEvent>
<boundaryEvent id="sid-973FE65A-C0AE-4072-AA92-83ED2CB42C6C" attachedToRef="eventSub" cancelActivity="false">
<cancelEventDefinition></cancelEventDefinition>
</boundaryEvent>
<serviceTask id="receiveCancel" name="接收取消操作" activiti:class="com.lyy.serviceTask.ReceiveCancel"></serviceTask>
<sequenceFlow id="sid-C552E510-5FDF-41B6-B6A0-4EF7C6878234" sourceRef="sid-973FE65A-C0AE-4072-AA92-83ED2CB42C6C" targetRef="receiveCancel"></sequenceFlow>
<sequenceFlow id="sid-82B61457-A6F7-4EE5-821B-60BBFADD3636" sourceRef="sid-FBF27FA9-358F-4921-BE80-4A1C41B3E2E7" targetRef="eventSub"></sequenceFlow>
<endEvent id="sid-6DDB28A5-C577-4814-9D1E-AFD886E0B702"></endEvent>
<sequenceFlow id="sid-EC15EB6D-9F73-4CC2-B70B-71069B513DFF" sourceRef="eventSub" targetRef="sid-6DDB28A5-C577-4814-9D1E-AFD886E0B702"></sequenceFlow>
<!-- 这条连线用来连接补偿边界事件和补偿的具体执行者,只能放在流程图的最后 -->
<association id="sid-D58DDE81-5384-43AF-9A16-FA3889A80DB5" sourceRef="sid-7003DABD-72C5-4570-9F28-717590290F0F" targetRef="cancelHuiKuan" associationDirection="None"></association>
</process>
</definitions>
2.4 终止结束事件
当流程执行到终止结束事件是当前的流程将会被终结,该事件可以在嵌入子流程,调用子流程,事件子流程,事务子流程中使用。它使用terminateEventDefinition
元素作为事件定义,如果将activiti:terminateAll
属性设置为true当终止结束事件触发时当前流程的全部执行流都会被终结,否则只会结束终止结束事件所在的执行流,
这个属性的默认值是false,
一个完整的终止结束事件定义示例如下
<endEvent id="sid-92098291-CE73-4876-A44C-EA2FEBA9CEED">
<terminateEventDefinition></terminateEventDefinition>
</endEvent>
上边这个流程在嵌入子流程中包含了一个终止结束事件,启动流程后一共会有4个执行流,
执行流1:主执行流,
执行流2:停在main task1上,parent是执行流1
执行流3:代表并行网关的上部分,parent是执行流1
执行流4:代表子流程,会停在sub task1上,parent是执行流3
如果该事件定义的activiti:terminateAll
属性是true,当sub task1审批完成后此流程的所有执行流都会结束。
如果该事件定义的activiti:terminateAll
属性是false,当sub task1审批完成后此流程只有执行流4结束了。
上述流程图完整的流程定义文件是
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="terminateEndEventTest" name="终止结束事件测试" isExecutable="true">
<startEvent id="sid-F3E272BF-D3CD-4531-A034-0DB11A407090"></startEvent>
<parallelGateway id="sid-A0B1A7E8-D9A9-4E96-BC97-240C47DC1AE4"></parallelGateway>
<sequenceFlow id="sid-31F7F199-C656-4B67-BBA6-E627E17824D4" sourceRef="sid-F3E272BF-D3CD-4531-A034-0DB11A407090" targetRef="sid-A0B1A7E8-D9A9-4E96-BC97-240C47DC1AE4"></sequenceFlow>
<subProcess id="sid-11856679-C141-452F-8ED1-CCC5C5B25EB1" name="子流程">
<startEvent id="sid-43EAB097-00FD-4A6C-AFBD-99891BB624B5"></startEvent>
<userTask id="subTask1" name="sub task1"></userTask>
<!-- 这里定义了终止结束事件 -->
<endEvent id="sid-92098291-CE73-4876-A44C-EA2FEBA9CEED">
<terminateEventDefinition activiti:terminateAll="true"></terminateEventDefinition>
</endEvent>
<sequenceFlow id="sid-CC2523D4-7FF9-494A-9AE0-30BFE45ECCBD" sourceRef="sid-43EAB097-00FD-4A6C-AFBD-99891BB624B5" targetRef="subTask1"></sequenceFlow>
<sequenceFlow id="sid-458660D3-B755-4E4A-B7DE-2BD5E8F8BFC5" sourceRef="subTask1" targetRef="sid-92098291-CE73-4876-A44C-EA2FEBA9CEED"></sequenceFlow>
</subProcess>
<sequenceFlow id="sid-4D82FB52-B0BC-4D50-A069-D459B48FA5AF" sourceRef="sid-A0B1A7E8-D9A9-4E96-BC97-240C47DC1AE4" targetRef="sid-11856679-C141-452F-8ED1-CCC5C5B25EB1"></sequenceFlow>
<userTask id="mainTask1" name="main task1"></userTask>
<sequenceFlow id="sid-F9747EFE-02F4-4241-A33B-2D8AA945E26A" sourceRef="sid-A0B1A7E8-D9A9-4E96-BC97-240C47DC1AE4" targetRef="mainTask1"></sequenceFlow>
<userTask id="mainTask2" name="main task2"></userTask>
<sequenceFlow id="sid-CE994662-3003-4900-8713-16A72200A33D" sourceRef="sid-11856679-C141-452F-8ED1-CCC5C5B25EB1" targetRef="mainTask2"></sequenceFlow>
<sequenceFlow id="sid-20D85F7E-BD12-4C83-A08E-3B7EF27D9A18" sourceRef="mainTask1" targetRef="mainTask2"></sequenceFlow>
<endEvent id="sid-99C9A8E7-DE9E-48EC-97D3-EBA653B496CA"></endEvent>
<sequenceFlow id="sid-98CE2C7D-DDDE-4904-8A61-F0879253FD7C" sourceRef="mainTask2" targetRef="sid-99C9A8E7-DE9E-48EC-97D3-EBA653B496CA"></sequenceFlow>
</process>
</definitions>
三、边界事件
边界事件需要附属在流程活动中,它是catching事件,会等待被触发,如果边界事件被触发当前的活动会被中断,当前的顺序流发生转移。
边界事件有cancelActivity属性,表示流程是否可中断。
可以通过boundaryEvent元素的cancelActivity属性为true表示可中断,
false不可中断,默认为false。
可中断: 原来的执行流会被从数据库删除
不可中断:原来的执行流不会被删除
3.1定时器边界事件
当流程到达了指定流程活动时定时器启动,定时器满足条件后被触发,流程就会从定时器边界事件离开流程活动。
定时器边界事件适合在一些限时的业务流程中使用。
上边这个流程含有一个定时器边界事件,设置了1分钟内初级工程师维修任务没完成就触发。
<boundaryEvent id="timerNoundaryEvent" name="定时器边界事件" cancelActivity="true" attachedToRef="userTask1">
<timerEventDefinition>
<timeDuration>PT1M</timeDuration>
</timerEventDefinition>
</boundaryEvent>
该事件触发后流程就会转到中级工程师维修这个任务上。
注意要实现这种效果启动流程后一定不能关闭流程引擎,只有流程引擎一直启动才能实现定时器效果。
并且创建流程引擎对象时一定要设置这几个属性为true
<property name="asyncExecutorActivate" value="true"></property>
<property name="jobExecutorActivate" value="true"></property>
<property name="asyncExecutorEnabled" value="true"></property>
完整的流程图如下
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="timerBounddaryEvent" name="定时器边界事件Test" isExecutable="true">
<startEvent id="sid-CFBE8411-C276-4A22-8DB3-9F93C67081ED"></startEvent>
<userTask id="userTask1" name="初级工程师维修" activiti:assignee="kermit"></userTask>
<sequenceFlow id="sid-27E7C031-43BF-42E4-9E32-BB62757250DB" sourceRef="sid-CFBE8411-C276-4A22-8DB3-9F93C67081ED" targetRef="userTask1"></sequenceFlow>
<endEvent id="sid-D606453E-A341-4A00-969C-DB2BA8A72B03"></endEvent>
<sequenceFlow id="sid-28187E72-359B-4929-AD4C-C91A9A5E7654" sourceRef="userTask1" targetRef="sid-D606453E-A341-4A00-969C-DB2BA8A72B03"></sequenceFlow>
<userTask id="userTask2" name="中级工程师维修" activiti:assignee="kermit"></userTask>
<sequenceFlow id="sid-9613E733-B083-4FC1-8DF4-EC1E3CCA99E0" sourceRef="timerNoundaryEvent" targetRef="userTask2"></sequenceFlow>
<sequenceFlow id="sid-5C4AB652-6DA3-458C-8A93-2134889AECC5" sourceRef="userTask2" targetRef="sid-D606453E-A341-4A00-969C-DB2BA8A72B03"></sequenceFlow>
<!-- 这里定义了一个定时器边界世界 -->
<boundaryEvent id="timerNoundaryEvent" name="定时器边界事件" cancelActivity="true" attachedToRef="userTask1">
<timerEventDefinition>
<!-- 1分钟后触发 -->
<timeDuration>PT1M</timeDuration>
</timerEventDefinition>
</boundaryEvent>
</process>
</definitions>
3.2 错误边界事件
错误边界事件依附在流程活动上,当流程活动抛出异常时会被捕获到然后触发,改变流程走向。
在使用错误边界事件时可以在错误事件定义中加入errorRef属性,
(1)如果不使用此属性,该边界事件会捕捉任何错误事件
(2)如果提供了该属性并指向了一个已经存在的error,该边界事件只会捕捉与该error有一样的errorCode的错误事件
(3)如果errorRef引用了一个不存在的error,那么引用的字符串将会被当做errorCode。
上边这个流程,在service task中抛出一个BpmnError就会改变流程的走向
完整的流程图如下,这里测试的是上边的第3种情况。
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="errorBoundaryEventTest" isExecutable="true">
<startEvent id="sid-1E1311FA-5FE5-461F-94EC-05DC3947FB8B"></startEvent>
<serviceTask id="serviceTask" name="service task" activiti:class="com.lyy.serviceTask.ThrowErrorServiceTask"></serviceTask>
<sequenceFlow id="sid-96F80823-B9C5-4C94-82D4-AAECAA068FA3" sourceRef="sid-1E1311FA-5FE5-461F-94EC-05DC3947FB8B" targetRef="serviceTask"></sequenceFlow>
<userTask id="endTask" name="end Task"></userTask>
<sequenceFlow id="sid-7BE68B71-25EF-4D74-9A23-34EE24C6F5F6" sourceRef="serviceTask" targetRef="endTask"></sequenceFlow>
<userTask id="errorTask" name="error task"></userTask>
<endEvent id="sid-23C4EA62-49C7-4D05-84BA-5825CDC97682"></endEvent>
<sequenceFlow id="sid-C2682272-750B-4A58-8CB2-BFECB6BC7CE9" sourceRef="endTask" targetRef="sid-23C4EA62-49C7-4D05-84BA-5825CDC97682"></sequenceFlow>
<sequenceFlow id="sid-9C49E1A2-E1CE-4A36-8A99-0BE80AA4E42F" sourceRef="errorTask" targetRef="sid-23C4EA62-49C7-4D05-84BA-5825CDC97682"></sequenceFlow>
<boundaryEvent id="sid-073D7855-DC12-4F66-9859-D057141D5C36" attachedToRef="serviceTask">
<errorEventDefinition errorRef="testError"></errorEventDefinition>
</boundaryEvent>
<sequenceFlow id="sid-2E283640-11CF-4853-B203-41F84038F697" sourceRef="sid-073D7855-DC12-4F66-9859-D057141D5C36" targetRef="errorTask"></sequenceFlow>
</process>
</definitions>
注意错误边界事件没有cancelActivity属性
3.3 信号边界事件
信号边界事件依附在流程活动中,它的触发条件时收到对应的信号,但信号具有全局性,activiti中发送信号时可以同时给所有的流程发送信号。信号边界事件有cancelActivity属性,表示流程是否可中断
activiti 的RuntimeService中提供了多种发送信号的方法
void signalEventReceived(String signalName);//全局发送
void signalEventReceived(String signalName, String executionId);//给指定的执行流发送信号
上边流程图描述的这个流程,在任务2时如果收到信号就会改变流程的走向
完整的流程图文件如下
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<signal id="signalBoundaryTest" name="signalBoundaryTest" activiti:scope="global"></signal>
<process id="signalBoundaryEventTest" name="信号变更事件测试" isExecutable="true">
<startEvent id="sid-B96CF1D9-2605-4C14-987D-89C11377E47E"></startEvent>
<userTask id="task1" name="任务1"></userTask>
<sequenceFlow id="sid-D64F612C-C0C6-4A04-BFC5-7EB3FCF19731" sourceRef="sid-B96CF1D9-2605-4C14-987D-89C11377E47E" targetRef="task1"></sequenceFlow>
<userTask id="task2" name="任务2"></userTask>
<sequenceFlow id="sid-0B7FA8BA-A3D8-4B24-81DB-77D279D1181E" sourceRef="task1" targetRef="task2"></sequenceFlow>
<endEvent id="sid-1C639486-07CF-427D-BE4A-37BEE0939F25"></endEvent>
<sequenceFlow id="sid-71E633A9-D485-46E6-8954-13A36A7DAEA2" sourceRef="task2" targetRef="sid-1C639486-07CF-427D-BE4A-37BEE0939F25"></sequenceFlow>
<boundaryEvent id="sid-787D664E-BDB2-4932-A22A-160ADE11C988" attachedToRef="task2" cancelActivity="true">
<signalEventDefinition signalRef="signalBoundaryTest"></signalEventDefinition>
</boundaryEvent>
<userTask id="task3" name="变更任务"></userTask>
<sequenceFlow id="sid-D04DDE2F-566E-4113-8541-7A08A1993DCD" sourceRef="sid-787D664E-BDB2-4932-A22A-160ADE11C988" targetRef="task3"></sequenceFlow>
<sequenceFlow id="sid-61B219F6-45D6-429B-BF45-148A1D5678A9" sourceRef="task3" targetRef="task1"></sequenceFlow>
</process>
省略图形位置信息
</definitions>
3.4 消息边界事件
消息边界事件和信号边界事件类似,但是一个消息只能被发送给一个流程。
RutimeService中提供了给流程发送消息的方法
void messageEventReceived(String messageName, String executionId);
消息边界事件定义的时候是边界事件元素+消息事件定义元素
<boundaryEvent id="sid-BA33E9F8-0148-4E3A-8D9E-1FE2277A429A" attachedToRef="task2" cancelActivity="true">
<messageEventDefinition messageRef="messageBoundaryEventTest"></messageEventDefinition>
</boundaryEvent>
流程图示例
3.5 补偿边界事件
补偿边界事件会在流程活动完成后根据情况(事务取消或者补偿中间事件触发)来触发,补偿边界事件会关联补偿的具体执行者,当补偿边界事件触发时具体的执行者就会执行。所以可以通过在事务子流程中用取消结束事件+取消边界事件来触发,也可以通过补偿中间事件来触发。
上边是一个补偿边界事件+补偿执行者+补偿中间事件的流程示例。在结果确认这个service中抛出错误被错误边界事件捕捉到,然后流程转到补偿中间事件触发补偿。注意流程执行时是先A后B而补偿执行的时候是先执行的service后补偿,所以是先B后A
完整的流程图如下,省略了图形信息的部分
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="compensateBoundaryTest" name="compensateBoundaryTest.bpmn" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
<serviceTask id="service1" name="A银行扣款"></serviceTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="service1"></sequenceFlow>
<serviceTask id="service2" name="B银行收款"></serviceTask>
<serviceTask id="service3" name="结果确认"></serviceTask>
<sequenceFlow id="flow2" sourceRef="service1" targetRef="service2"></sequenceFlow>
<sequenceFlow id="flow3" sourceRef="service2" targetRef="service3"></sequenceFlow>
<boundaryEvent id="boundaryerror1" name="Error" attachedToRef="service3">
<errorEventDefinition></errorEventDefinition>
</boundaryEvent>
<intermediateThrowEvent id="compensationintermediatethrowevent1" name="CompensationThrowingEvent">
<compensateEventDefinition></compensateEventDefinition>
</intermediateThrowEvent>
<sequenceFlow id="flow4" sourceRef="boundaryerror1" targetRef="compensationintermediatethrowevent1"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow5" sourceRef="service3" targetRef="endevent1"></sequenceFlow>
<endEvent id="endevent2" name="End"></endEvent>
<sequenceFlow id="flow6" sourceRef="compensationintermediatethrowevent1" targetRef="endevent2"></sequenceFlow>
<boundaryEvent id="boundarycompensation1" name="Compensate" attachedToRef="service1" cancelActivity="true">
<compensateEventDefinition></compensateEventDefinition>
</boundaryEvent>
<boundaryEvent id="boundarycompensation2" name="Compensate" attachedToRef="service2" cancelActivity="true">
<compensateEventDefinition></compensateEventDefinition>
</boundaryEvent>
<serviceTask id="service4" name="补偿A" isForCompensation="true"></serviceTask>
<serviceTask id="service5" name="补偿B" isForCompensation="true"></serviceTask>
<association id="association1" sourceRef="boundarycompensation1" targetRef="service4"></association>
<association id="association2" sourceRef="boundarycompensation2" targetRef="service5"></association>
</process>
</definitions>
四、中间事件
中间事件是可以单独作为流程元素的事件,分为两种,catching事件(等待被触发)和throw事件(直接抛出事件),
使用 intermediateThrowEvent或者intermediateCatchEvent加事件定义元素来表示
4.1定时器中间事件
这是一个catching事件,会一直等待被触发,当时间到达后被触发
4.2 信号中间catching事件
等待被触发
4.3 信号中间throwing事件
抛出事件发送信号,信号中间catching和信号中间throw经常配合使用,在同一个流程中一个分支等待信号,另一分支发送信号。
4.4 消息中间事件
activit仅支持消息中间catching事件
4.5 无指定中间事件
它是一个throw事件,它中间没有指定任何的事件定义,看起来没有任何作用,但可以改它配置流程监听器来使用。
4.6 补偿中间事件
补偿中间事件用来粗发补偿边界事件,进而触发补偿