1 事件分类
1.1 按照事件的位置分类
开始事件:表示流程开始的事件
结束事件:表示流程结束的事件
中间事件:出现在流程中,单独作为流程节点的事件
1.2 按照事件的特性分类
Catching事件:会一直等待被触发
Throwing事件:会自动触发并反馈结果
2.事件定义
2.1 定时器事件定义
定时器事件是由定时器触发的事件,定时器事件的定义可以嵌套在开始事件,中间事件或者边界事件中.配置如下:
<timerEventDefinition>
<timeDate>2018-10-10T06:00:00</timeDate>
</timerEventDefinition>
<timerEventDefinition>
<timeDuration>PT5S</timeDuration>
</timerEventDefinition>
<timerEventDefinition>
<timeCycle>R2/PT1M</timeCycle>
</timerEventDefinition>
以上三个timerEventDefinition的子元素,在定义时间时,都需要遵守ISO 8601的国际标准,该标准是关于日期和时间的表示方法的标准,其中timeCycle还支持使用cron表达式来设定定时器的重复间隔.
2.2 错误事件定义
错误事件会被定义的错误信息所触发,BPMN中的错误事件主要用于处理流程中出现的业务异常.流程中的业务异常与Java中的Exception是不同的概念,在设计业务时,如果满足一定的条件,那么就会触发错误事件.
<error id="myError" errorCode="123"></error>
<process id="testProcess" name="testProcess">
<endEvent id="myErrorEndEvent">
<errorEventDefinition errorRef="myError"/>
</endEvent>
</process>
BPMN规范规定一个error元素需要包含以下属性
id:该元素的唯一标识
name:元素的名称
errorCode:错误事件编码,当处理业务时抛出相应的异常代码,流程引擎会根据该错误代码自动匹配到该error元素,定义error元素必须设定errorCode属性
structureRef:结构引用属性
2.3 信号事件定义
信号事件是一种引用了信号定义的事件,可以使用一个信号向全部的流程发送广播(前提是流程定义使用了同样名称的信号),信号事件的xml配置如下:
<signal id="signalA" name="signalA"></signal>
<process id="testProcess" name="testProcess">
...
<signalEventDefintion signalRef="signalA"></signalEventDefinition>
...
</process>
id:该元素的唯一标识,必须提供
name:signal元素的名称,必须提供,否则Activiti在解析流程文件时会抛出异常,在一个流程定义中,不允许同时出现多个name相同的signal元素,否则将抛出异常
structureRef:该属性与错误事件的structureRef属性一样
2.4 消息事件定义
消息事件是一种引用了消息定义的事件,与信号不同的是,消息只能指向一个接收人,而不能像信号一样进行广播.使用messageRef属性引用一个消息(引用消息元素的id);
<message id="myMsg" name="myMsg"></message>
<process id="medProcess" name="medProcess">
...
<messageEventDefinition messageRef="myMsg"></messageEventDefinition>
...
</process>
id:该元素的唯一标识
name:消息的名称,使用RuntimeService的messageEventReceived方法时传入该参数
itemRef:用于指定该消息引用的itemDefinition元素
2.5 取消事件定义
取消事件使用在事务子流程(Transaction Sub-Process)模型中,取消事件定义可以使用在边界事件和结束事件中,称为取消边界事件和取消结束时间
<cancelEventDefinition></cancelEventDefinition>
2.6 补偿事件定义
补偿机制主要用于对已经成功完成的流程做回退处理,因为这些流程的结果吗有可能不是我们所期望的,如果当前流程活动时激活状态的,那么不能使用补偿机制,但是可以考虑取消机制,相反,取消友可能会导致补偿的触发.
<compensateEventDefinition><compensateEventDefinition/>
3 开始事件
3.1 无指定开始事件
没有为其指定任务触发条件的开始事件为无指定开始事件,使用无指定开始事件,流程引擎并不知道流程将会在什么时候开始,如果需要启动流程,就必须使用RuntimeService的startProcessByXXX方法.
<process id="timerStartProcess" name="timerStartProcess">
<startEvent id="startEvent1" name="start"></startEvent>
<userTask id="userTask1" name="task"></userTask>
<endEvent id="endEvent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startEvent1" targetRef="userTask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="userTask1" targetRef="endEvent1"></sequenceFlow>
</process>
3.2 定时器开始事件
在开始事件中加入定时器事件定义,该开始事件就成为一个定时器开始事件,当时符合条件,流程启动,而并不需要像无指定开始事件一样,使用API启动流程
<process id="timerStartProcess" name="timerStartProcess">
<startEvent id="timerstartevent1" name="Timer start">
<timerEventDefinition>
<timeCycle>0/5 * * * * ?</timeCycle>
</timerEventDefinition>
</startEvent>
<userTask id="userTask1" name="check log"></userTask>
<endEvent id="endEvent1" name="end"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="timerstartevent1" targetRef="userTask1"></sequence>
<sequenceFlow id="flow2" name="" sorrceRef="usertask1" targetRef="endevent1"></sequenceFlow>
</process>
3.3 消息开始事件
为开始事件加入消息事件的定义可以使其成为消息开始事件,此时可以使用RuntimeService的startProcessByMessage方法启动流程
<message id="msgA"></message>
<process id="myProcess" name="myProcess">
<userTask id="userTask1" name="myTask"></userTask>
<endTask id="endevent1" name="End"></endEvent>
<startEvent id="messagestartevent1" name="Message start">
<messageEventDefintion messageRef="msgA"></messageEventDefinition>
</startEvent>
<sequenceFlow id="flow1" name="" sourceRef="messagestartevent1" targetRef="userTask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="userTask1" targetRef="endevent1"></sequenceFlow>
</process>
//部署流程文件
repositoryService.createDeployment().addClasspathResource("bpmn/MessageStartEvent.bpmn").deploy();
//启动流程
runtimeService.startProcessInstanceByMessage("msgA");
//查询流程
runtimeService.createProcessInstanceQuery().count();
3.4 错误开始事件
错误开始事件只能在事件子流程中使用,该事件不能在其他的流程中使用,包括最高级流程(Top-Level Process),嵌套子流程(Sub-Process)和调用子流程(Call Activity).
假设当前有一个检查服务器8080端口的流程,当流程启动后,会检查服务器的8080端口是否存在,如果不存在,则执行事件子流程,对应的流程图和代码如下:
<error id="" errorCode="error"></error>
<Process id="errorStartProcess" name="errorStartProcess">
<startEvent id="startEvent1" name="Start"></startEvent>
<subProcess id="eventProcess1" name="Event sub Process" triggeredByEvent="true">
<startEvent id="errorstartevent1" name="Error start">
<errorEventDefintion errorRef="connectError"></errorEventDefinition>
</startEvent>
<serviceTask id="userTask1" name="Sub Task" activiti:class="org.crazyit.activiti.HandleErrorDelegate"></serviceTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow2" name="" sourceRef="errorstartevent1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow3" name="" sourceRef="usertask1" targetRef="endevent1"></sequenceFLow>
</subprocess>
<serviceTask id="servicetask1" name="Service Task" activiti:class="org.crazyit.activiti.CheckServerDelegate"></serviceTask>
<endEvent id="endevent2" name="End"></endEvent>
<sequenceFlow id="flow4" name="" sourceRef="startevent1" targetRef="serviceTask1"></sequenceFlow>
<sequenceFlow id="flow5" name="" sourceRef="servicetask1" targetRef="endevent2"></sequenceFlow>
</process>
CheckServerDelegate.java
try{
System.out.println("开始检查8080端口");
//连接本机的8080端口
Socket socket = new Socket("127.0.0.1",8080);
System.out.println("检查8080端口完成");
}catch(Exception e){
System.out.println("检查时出现异常, 抛出错误");
//连接出现异常,则抛出BpmError,且error code为"error"
throw new org.activiti.engine.delegate.BpmnError("error");
}
4 结束事件
4.1 无指定结束事件
与无指定开始事件一样,无指定结束事件是指流程在结束时,不会进行任务的额外操作,结束事件中不使用任何事件的定义.
<process id="myProcess" name="myProcess">
<startEvent id="startEvent1" name="Start"></startEvent>
<userTask id="userTask1" name="User Task"></userTask>
<endEvent id="endEvent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="usertask1"></sequenceFLow>
<sequenceFlow id="flow2" name="" sourceRef="userTask1" targetRef="endevent1"></sequenceFlow>
</process>
4.2 错误结束事件
当执行流到达错误结束事件时,会结束该执行流并且抛出错误,该错误可以被"错误边界事件"捕获,如果没有定义任何的错误边界事件,那么其将会被当作无指定错误事件执行,因此,错误结束事件一般在子流程当中使用.错误事件结束后,就会触发依附在该子流程上的错误边界事件.
// 部署流程文件
repositoryService.createDeployment().addClasspathResource("bpmn/ErrorEndEvent.bpmn").deploy();
// 启动流程
runtimeService.startProcessInstanceByKey("errorEndProcess");
//结束子流程中的任务,并设置结束任务
Task subTask = taskService.createTaskQuery().singleResult();
Map<String,Object> vars = new HashMap<String,Object>();
//设置success参数为true
vars.put("success","true");
taskService.complete(sybTask.getId(),vars);
//查看到达的任务
List<Task> tasks = taskService.createTaskQuery().list();
for(Task task : tasks){
System.out.println(task.getName());
}
4.3 取消结束事件和取消边界事件
取消结束事件只能在事务子流程中使用,该事件表示事务将会取消,并且会触发依附在事务子流程上的取消边界事件,与错误结束事件类似,取消结束事件会被抛出,而取消边界事件则会捕获该事件.事务子流程的取消事件的触发,还会导致补偿的触发.
//部署流程文件
repositoryService.createDeployment().addClasspathResource("bpmn/CancelEndEvent.bpmn").deploy();
//启动流程
runtimeService.startProcessInstanceByKey("cancleProcess");
//初始化流程参数
Map<String,Object> vars = new HashMap<String,Object>();
vars.put("confirm",false);
// 设置参数,完成用户确认的task
Task task = taskService.createTaskQuery().singleResult();
taskService.complete(task.getId(),vars);
4.4 中止结束事件
当流程执行到终止结束事件时,当前的流程将会被终结,该事件可以在嵌入子流程,调用子流程,事件子流程或者事务子流程中使用…终止结束事件使用terminateEventDefinition元素作为事件定义.如果将元素的activiti:terminateAll属性设置为true,bane当终止结束事件被触发时,流程实例的全部执行流均会被终结.
...//部署流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("terminateAll");
//查询执行流数量
long exeCount = runtimeService.createExecutionQuery().processInstanceId(pi1.getId()).count();
5 边界事件
BPMN2.0中定义了以下边界事件:消息(Message)边界事件,定时器边界事件,升级边界事件,错误边界事件,取消边界事件,补偿边界事件,条件边界事件,信号边界事件,组合边界事件和并行组合边界事件
6 中间事件
中间事件按照其特性可以分为两类:中间catching事件和Throwing事件,当流程到达中间Catching事件时,它会一直等待,直到接收信息,还会被触发,而当流程到达中间Throwing事件时,该事件会自动触发并抛出相应的结果或者信息.