Activiti事件主要包含两个概念:事件类型与事件定义。事件类型分为抛出型和捕获型,事件类型描述了事件发生的位置。对于捕获型事件,事件定义描述了事件被触发的时机;对于抛出型事件,事件定义描述了到达节点时发生的事件行为。
下面通过最常见的开始事件和结束事件找找感觉。
开始事件
开始事件指明了流程的起点,开始事件属于捕获型事件,当捕获到某种“信号”时发起一个新流程,这个“信号”可以是时间、消息或者是异常。
开始事件可以指定在2017-10-13T00:00:00
发起流程:
<startEvent id="start" name="my start event">
<timerEventDefinition>
<timeDate>2017-10-13T00:00:00</timeDate>
</timerEventDefinition>
</startEvent>
也可以指定收到某个消息时发起流程:
<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" />
<process id="invoiceProcess">
<startEvent id="messageStart" >
<messageEventDefinition messageRef="newInvoice" />
</startEvent>
...
</process>
</definitions>
然后在代码中通过runtimeService.startProcessInstanceByMessage(String messageName)
触发事件。
也可以不给开始事件指定任何事件定义(None Start Event):
<startEvent id="start" name="my start event" />
这种无事件定义的开始事件,只能通过runtimeService.startProcessInstanceByKey("someProcessKey")
来发起。
结束事件
结束事件是流程的终点,结束事件属于抛出型事件,可以在到达结束事件节点时传播一个错误:
<endEvent id="myErrorEndEvent">
<errorEventDefinition errorRef="myError" />
</endEvent>
也可以中断流程实例:
<endEvent id="myEndEvent >
<terminateEventDefinition activiti:terminateAll="true"></terminateEventDefinition>
</endEvent>
代码实现
下面以消息开始事件和错误结束事件为例,看一下activiti框架的具体实现。
在流程图xml中,所有事件定义都以事件子节点的形式存在,而在Activiti框架中所有子节点的解析类都继承了BaseChildElementParser
类。所以很快可以定位了消息事件定义和错误事件定义的解析器MessageEventDefinitionParser
和ErrorEventDefinitionParser
。
从代码实现上,两个Parser并没有太大区别,都是解析xml内容,然后生成对应的EventDefinition
,并添加到当前节点下:
((Event) parentElement).getEventDefinitions().add(eventDefinition);
在开始事件的handler处理步骤中,会获取解析出来的eventDefinition对象,调用对应的handler进行处理:
if (!startEvent.getEventDefinitions().isEmpty()) {
EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0);
if (eventDefinition instanceof TimerEventDefinition
|| eventDefinition instanceof MessageEventDefinition
|| eventDefinition instanceof SignalEventDefinition) {
bpmnParse.getBpmnParserHandlers().parseElement(bpmnParse, eventDefinition);
} else {
logger.warn("Unsupported event definition on start event", eventDefinition);
}
}
消息事件定义对应handler是MessageEventDefinitionParseHandler
,在handler中会为消息事件定义创建订阅关系,并最终在BpmnDeployer
中以EventSubscriptionEntity
实例形式落库。
当调用org.activiti.engine.impl.RuntimeServiceImpl#startProcessInstanceByMessage(java.lang.String)
时,会从根据消息名称查询对应的EventSubscriptionEntity
,获取其中的ProcessDefinitionId并发起流程。
结束事件的handler处理稍微有些区别,在结束事件的EndEventParseHandler
中会判断是否包含事件定义和事件定义的类型:
if (eventDefinition instanceof org.activiti.bpmn.model.ErrorEventDefinition) {
org.activiti.bpmn.model.ErrorEventDefinition errorDefinition = (org.activiti.bpmn.model.ErrorEventDefinition) eventDefinition;
if (bpmnParse.getBpmnModel().containsErrorRef(errorDefinition.getErrorCode())) {
String errorCode = bpmnParse.getBpmnModel().getErrors().get(errorDefinition.getErrorCode());
if (StringUtils.isEmpty(errorCode)) {
logger.warn("errorCode is required for an error event " + endEvent.getId());
}
endEventActivity.setProperty("type", "errorEndEvent");
errorDefinition.setErrorCode(errorCode);
}
endEventActivity.setActivityBehavior(bpmnParse.getActivityBehaviorFactory().createErrorEndEventActivityBehavior(endEvent, errorDefinition));
}
当事件定义是错误事件定义时,创建了ErrorEndEventActivityBehavior
,并赋予了结束事件对应的ActivityImpl。
从代码实现上看,捕获型事件本质是一种订阅关系,订阅的对象可以是信号、消息、时间。而抛出型事件本质是一种特定的行为,行为可以是传播异常、终止流程等