activiti中的事件

发布时间 2023-07-02 20:52:25作者: 程序晓猿

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>