天行有常,不为尧存,不为桀亡。——荀子《天论》
官方站点:http://www.omg.org/
BPMN包 | 说明 |
---|---|
BPMN核心元素 | 包含基础结构、基础、公共和服务中定义的元素包。 |
流程图 | 包含流程、活动、数据和人员交互中定义的元素。 |
协作图 | 包括池和消息流。 |
会话图 | 包含池、会话和会话链接。 |
完整建模一致性,BPMN中定义了三个子类:
原文 | 子类 | 说明 |
---|---|---|
Descriptive | 描述性 | 和高级建模中可见元素和属性有关。 |
Analytic | 分析性 | 包含完整过程建模中符合所有描述性的元素等。 |
Common Executable | 通用可执行文件 | 专注于可执行流程模型所需元素。 |
BPMN 2.0不支持编排模型,下边表格为XML中的Element和Attribute。
支持子类的工具必须满足下边条件:
详细内容参考附件中的
2.2.2 BPMN Process Elements
以下是从BPMN 1.2扩展的范围和功能:
以下是超出国际标准范围的部分:
端到端BPMN模型中存在三种子模型:
私有进程有两种类型:可执行/不可执行——不可执行流程是已建模的专用流程,目的是在建模者定义的详细级别上记录流程行为。
公共流程表示私有业务流程与另一个流程或参与者之间的交互,公共流程中仅包括那些用于与其他参与者交流的活动,原图中没有下边这个框,Modeler中目前没找到绘制的方法(下边是原图)。
协作描述了两个或多个业务实体之间的交互,通常包含两个或多个池,代表协作中的参与者,此时直接连接池中对象。
独立的组合流程(无池或编排)表示交互参与者之间预期行为的定义,一般为程序上的契约,它看起来比较像私有业务流程,由活动、事件和网关组成。编排和私有不同的地方是一个“活动”代表一组消息交换的交互,涉及两个或多个参与者(中英双份)。
会话图是协作图中的一种特殊用法,也是对协作图的非正式描述,但会话中不包含流程,通常不会在“对话”图的池之间放置编排(中英双份)。
BPMN元素的五个基本类别:
元素 | 符号 | 扩展符号 | |
---|---|---|---|
Event | ![]() |
![]() |
|
Type Dimension | 参考表格之后的完整定义表 | ||
Activity | ![]() |
||
Task(Atomic) | ![]() |
||
Choreography Task | ![]() |
||
Process/Sub-Process(non-atomic) | 参考之后四个子流程 | ||
Collapsed Sub-Process | ![]() |
||
Expanded Sub-Process | ![]() |
||
Collapsed Sub-Choreography | ![]() |
||
Expanded Sub-Choreography | ![]() |
||
Gateway | ![]() |
||
Gateway Control Types | ![]() |
||
Sequence Flow | ![]() |
||
Normal Flow | ![]() |
||
Uncontrolled Flow | ![]() |
||
Conditional Flow | ![]() |
||
Default Flow | ![]() |
||
Exception Flow | ![]() |
||
Message Flow | ![]() |
||
Association | ![]() |
||
Compensation Association | ![]() |
||
Pool | ![]() |
||
Lane | ![]() |
||
Data Object | ![]() |
||
Data Object | ![]() |
||
Message | ![]() |
||
Group | ![]() |
||
Text Annotation | ![]() |
||
以下元素是非基本元素扩展 | |||
Fork | ![]() |
||
Join | ![]() |
||
Decision, Branching Point | 查看下边四种(选择类控制流程) | ||
Exclusive | ![]() |
||
Event-Based | ![]() |
||
Inclusive | ![]() |
||
Merging | ![]() |
||
Looping | 查看下边两种(循环类控制流程) | ||
Activity Looping | ![]() |
||
Sequence Flow Looping | ![]() |
||
Multiple Instances | ![]() |
||
Process Break | ![]() |
||
Transaction | ![]() |
||
Nested/Embedded Sub-Process | 无图标对应 | ||
Off-Page Connector | ![]() |
完整定义表
以下是使用BPMN 2.0可以建模的业务流程示例:
o
符号表示这个对象之间可以直接做连接。
From/To | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
---|---|---|---|---|---|---|
![]() |
‰ | o | o | o | o | |
![]() |
‰ | o | o | o | o | |
![]() |
‰ | o | o | o | o | |
![]() |
‰ | o | o | o | o | |
![]() |
‰ | o | o | o | o | |
![]() |
From/To | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
---|---|---|---|---|---|---|
![]() |
||||||
![]() |
^ | o | o | o | o | |
![]() |
^ | o | o | o | o | |
![]() |
^ | o | o | o | o | |
![]() |
^ | o | o | o | o | |
![]() |
^ | o | o | o | o |
核心包含四个子包:
其他所有详细内容和原理参考附件中的其他部分,本文主要处理图形部分,然后结合Camunda教程定义相关流程以及在产品中集成这部分内容。
四种定义和Java调用逻辑:
定义一个实现了JavaDelegate
或ActivityBehavior
接口的类,camunda:class
:
<serviceTask id="javaService"
name="My Java Service Task"
camunda:class="org.camunda.bpm.MyJavaDelegate" />
使用表达式解析一个delegation
的Java对象,camunda:delegateExpression
:
<serviceTask id="beanService"
name="My Bean Service Task"
camunda:delegateExpression="${myDelegateBean}" />
调用方法表达式或值表达式,camunda:expression
:
<serviceTask id="expressionService"
name="My Expression Service Task"
camunda:expression="${myBean.doWork()}" />
还有一种调用方法是直接使用REST/SOAP
接口,camunda:connector
。
您可以将执行结果存储在变量中:
<serviceTask id="aMethodExpressionServiceTask"
camunda:expression="#{myService.doSomething()}"
camunda:resultVariable="myVar" />
<serviceTask id="anExternalServiceTask"
camunda:type="external"
camunda:topic="ShipmentProcessing" />
发送任务主要用来发送一个消息出去。
<sendTask id="sendTask" camunda:class="org.camunda.bpm.MySendTaskDelegate" />
用户任务必须被人工执行和处理:
<userTask id="theTask" name="Important task" />
<userTask id="theTask" name="Schedule meeting" >
<documentation>
Schedule an engineering meeting for next week with the new hire.
</documentation>
// Java代码
task.getDescription();
下边片段用来定义该任务的最后期限:
<userTask id="theTask" name="Important task" camunda:dueDate="${dateVariable}"/>
下边片段用来定义下一个任务执行的时间:
<userTask id="theTask" name="Important task" camunda:followUpDate="${dateVariable}"/>
人工执行:Human Performer
<userTask id='theTask' name='important task' >
<humanPerformer>
<resourceAssignmentExpression>
<formalExpression>kermit</formalExpression>
</resourceAssignmentExpression>
</humanPerformer>
</userTask>
// Java代码
List<Task> tasks = taskService.createTaskQuery().taskAssignee("kermit").list();
可能拥有者:Potential Owner
<userTask id='theTask' name='important task' >
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>user(kermit), group(management)</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
// Java代码
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit");
下边两段代码是等价的:
<formalExpression>accountancy</formalExpression>
<formalExpression>group(accountancy)</formalExpression>
被派工者:Assignee
<userTask id="theTask" name="my task" camunda:assignee="kermit" />
候选用户:Candidate Users
<userTask id="theTask" name="my task" camunda:candidateUsers="kermit, gonzo" />
候选组:Condidate Groups
<userTask id="theTask" name="my task" camunda:candidateGroups="management, accountancy" />
组合候选用户和组
流程变量
<startEvent id="startEvent" camunda:initiator="starter" />
<userTask id="task" name="Clarify Invoice" camunda:assignee="${ starter }"/>
调用服务/Bean
<userTask id="task" name="My Task" camunda:assignee="${ldapService.findManagerForEmployee(emp)}"/>
<userTask id="task" name="My Task" camunda:candidateUsers="${ldapService.findAllSales()}"/>
// Java代码
public class FakeLdapService {
public String findManagerForEmployee(String employee) {
return "Kermit The Frog";
}
public List<String> findAllSales() {
return Arrays.asList("kermit", "gonzo", "fozzie");
}
}
监听器派工
<userTask id="task1" name="My task" >
<extensionElements>
<camunda:taskListener event="create" class="org.camunda.bpm.MyAssignmentHandler" />
</extensionElements>
</userTask>
// Java代码
public class MyAssignmentHandler implements TaskListener {
public void notify(DelegateTask delegateTask) {
// Execute custom identity lookups here
// and then for example call following methods:
delegateTask.setAssignee("kermit");
delegateTask.addCandidateUser("fozzie");
delegateTask.addCandidateGroup("management");
// ...
}
}
// 标识服务
ProcessEngine processEngine = delegateTask.getProcessEngine();
IdentityService identityService = processEngine.getIdentityService();
List<User> managementUsers = identityService.createUserQuery()
.memberOfGroup("management")
.list();
User kermit = identityService.createUserQuery()
.userFirstName("kermit")
.singleResult();
// 调用任务完成代码
taskService.complete(taskId, variables);
// or complete and retrieve the process variables
VariableMap processVariables = taskService
.completeWithVariablesInReturn(taskId, variables, shouldDeserializeValues);
属性camunda:decisionRefBinding
的值列表如下:
latest:最新版
<!-- 默认值 -->
<businessRuleTask id="businessRuleTask"
camunda:decisionRef="myDecision" />
version:使用指定版本,配合camunda:decisionRefVersion
<businessRuleTask id="businessRuleTask"
camunda:decisionRef="myDecision"
camunda:decisionRefBinding="version"
camunda:decisionRefVersion="12" />
<!-- 使用变量 -->
<businessRuleTask id="businessRuleTask"
camunda:decisionRef="${decisionKey}"
camunda:decisionRefBinding="version"
camunda:decisionRefVersion="${decisionVersion}" />
camunda:decisionRefVersionTag
使用map
数据结构处理决策结果:
<businessRuleTask id="businessRuleTask"
camunda:decisionRef="myDecision"
camunda:mapDecisionResult="singleEntry"
camunda:resultVariable="result" />
默认情况tenant id=null
,显示指定的情况:
camunda:decisionRefTenantId
指定
<businessRuleTask id="businessRuleTask" decisionRef="myDecision"
camunda:decisionRefTenantId="TENANT_1">
</businessRuleTask>
如果tenant id
未设计过:
<businessRuleTask id="businessRuleTask" decisionRef="myDecision"
camunda:decisionRefTenantId="${ myBean.calculateTenantId(variable) }">
</businessRuleTask>
调用流程实例:
<businessRuleTask id="businessRuleTask" decisionRef="myDecision"
camunda:decisionRefTenantId="${ execution.tenantId }">
</businessRuleTask>
<businessRuleTask id="businessRuleTask"
camunda:delegateExpression="${MyRuleServiceDelegate}" />
脚本任务定义(基于JSR-223
):
<scriptTask id="theScriptTask" name="Execute script" scriptFormat="groovy">
<script>
sum = 0
for ( i in inputArray ) {
sum += i
}
</script>
</scriptTask>
脚本中的变量(和Java交互):
<!-- 从Java代码中读 -->
<script>
sum = 0
for ( i in inputArray ) {
sum += i
}
</script>
<!-- 将代码写入Java代码 -->
<script>
sum = 0
for ( i in inputArray ) {
sum += i
}
execution.setVariable("sum", sum);
</script>
如果属性autoStoreScriptVariables=true
则流程引擎会自动存储全局脚本变量,该功能为7.0/7.1
版本中的默认功能。Script中的结果提取:
<scriptTask id="theScriptTask" name="Execute script"
scriptFormat="juel" camunda:resultVariable="myVar">
<script>#{echo}</script>
</scriptTask>
这种类型的任务通常会跟随一个message
引用:
<definitions ...>
<message id="newInvoice" name="newInvoiceMessage"/>
<process ...>
<receiveTask id="waitState" name="wait" messageRef="newInvoice">
...
Java代码中操作消息:
// correlate the message
runtimeService.createMessageCorrelation(subscription.getEventName())
.processInstanceBusinessKey("AB-123")
.correlate();
// 订阅和触发
ProcessInstance pi = runtimeService.startProcessInstanceByKey("processWaitingInReceiveTask");
EventSubscription subscription = runtimeService.createEventSubscriptionQuery()
.processInstanceId(pi.getId()).eventType("message").singleResult();
runtimeService.messageEventReceived(subscription.getEventName(), subscription.getExecutionId());
任务等待:
<receiveTask id="waitState" name="wait" />
// Java代码调用
ProcessInstance pi = runtimeService.startProcessInstanceByKey("receiveTask");
Execution execution = runtimeService.createExecutionQuery()
.processInstanceId(pi.getId()).activityId("waitState").singleResult();
runtimeService.signal(execution.getId());
手工任务主要定义外置BPM引擎逻辑,用于手工执行该任务。
<manualTask id="myManualTask" name="Manual Task" />
下边“活动(Activities)”实例可用来做多任务实例:
并行和串行专用任务:
属性表:
属性名 | 含义 |
---|---|
nrOfInstances | 实例总数量 |
nrOfActiveInstances | 当前激活的实例总数,如果是顺序型,则通常是1 |
nrOfCompletedInstances | 已经完成的实例数 |
For Each
迭代循环时迭代的索引值。<!--编排-->
<multiInstanceLoopCharacteristics isSequential="false|true">
</multiInstanceLoopCharacteristics>
<!--所有数值实例会计算一次-->
<multiInstanceLoopCharacteristics isSequential="false|true">
<loopCardinality>5</loopCardinality>
</multiInstanceLoopCharacteristics>
<!--也可以使用负值-->
<multiInstanceLoopCharacteristics isSequential="false|true">
<loopCardinality>${nrOfOrders-nrOfCancellations}</loopCardinality>
</multiInstanceLoopCharacteristics>
用户定义中使用编排:
<!--串行-->
<userTask id="miTasks" name="My Task ${loopCounter}" camunda:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false">
<loopDataInputRef>assigneeList</loopDataInputRef>
<inputDataItem name="assignee" />
</multiInstanceLoopCharacteristics>
</userTask>
<!--并行-->
<userTask id="miTasks" name="My Task" camunda:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="true"
camunda:collection="${myService.resolveUsersForTask()}" camunda:elementVariable="assignee" >
</multiInstanceLoopCharacteristics>
</userTask>
// 脚本处理
var collection = S('{ "collection" : ["System 1", "System 3"] }');
execution.setVariable("collection", collection);
<!--Xml定义-->
<multiInstanceLoopCharacteristics
camunda:collection="${collection.prop('collection').elements()}"
camunda:elementVariable="collectionElem" />
<!--对应定义-->
<exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" default="flow4" />
<sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1" name="${x==1}">
<conditionExpression xsi:type="tFormalExpression">${x == 1}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2" name="${x==2}">
<conditionExpression xsi:type="tFormalExpression">${x == 2}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3" name="else">
</sequenceFlow>
<sequenceFlow id="flow" sourceRef="theStart" targetRef="theTask">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${order.price > 100 && order.price < 250}]]>
</conditionExpression>
</sequenceFlow>
条件示例设置:
JavaBean风格:
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${order.price > 100 && order.price < 250}]]>
</conditionExpression>
直接调用相关方法:
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${order.isStandardOrder()}]]>
</conditionExpression>
Groovy脚本:
<conditionExpression xsi:type="tFormalExpression" language="groovy">
<![CDATA[status == 'complete']]>
</conditionExpression>
外置脚本引用:
<conditionExpression xsi:type="tFormalExpression" language="groovy"
camunda:resource="org/camunda/bpm/exampe/condition.groovy" />
两种类型:
<!-- 定义 -->
<parallelGateway id="myParallelGateway" />
<!-- 流程定义 -->
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
<parallelGateway id="fork" />
<sequenceFlow sourceRef="fork" targetRef="receivePayment" />
<sequenceFlow sourceRef="fork" targetRef="shipOrder" />
<userTask id="receivePayment" name="Receive Payment" />
<sequenceFlow sourceRef="receivePayment" targetRef="join" />
<userTask id="shipOrder" name="Ship Order" />
<sequenceFlow sourceRef="shipOrder" targetRef="join" />
<parallelGateway id="join" />
<sequenceFlow sourceRef="join" targetRef="archiveOrder" />
<userTask id="archiveOrder" name="Archive Order" />
<sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />
<endEvent id="theEnd" />
// Java代码
ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
TaskQuery query = taskService.createTaskQuery()
.processInstanceId(pi.getId())
.orderByTaskName()
.asc();
List<Task> tasks = query.list();
assertEquals(2, tasks.size());
Task task1 = tasks.get(0);
assertEquals("Receive Payment", task1.getName());
Task task2 = tasks.get(1);
assertEquals("Ship Order", task2.getName());
两种类型:
<!--定义-->
<inclusiveGateway id="myInclusiveGateway" />
<!-- 流程定义 -->
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
<inclusiveGateway id="fork" />
<sequenceFlow sourceRef="fork" targetRef="receivePayment" >
<conditionExpression xsi:type="tFormalExpression">${paymentReceived == false}</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="fork" targetRef="shipOrder" >
<conditionExpression xsi:type="tFormalExpression">${shipOrder == true}</conditionExpression>
</sequenceFlow>
<userTask id="receivePayment" name="Receive Payment" />
<sequenceFlow sourceRef="receivePayment" targetRef="join" />
<userTask id="shipOrder" name="Ship Order" />
<sequenceFlow sourceRef="shipOrder" targetRef="join" />
<inclusiveGateway id="join" />
<sequenceFlow sourceRef="join" targetRef="archiveOrder" />
<userTask id="archiveOrder" name="Archive Order" />
<sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />
<endEvent id="theEnd" />
// Java代码
HashMap<String, Object> variableMap = new HashMap<String, Object>();
variableMap.put("receivedPayment", true);
variableMap.put("shipOrder", true);
ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
TaskQuery query = taskService.createTaskQuery()
.processInstanceId(pi.getId())
.orderByTaskName()
.asc();
List<Task> tasks = query.list();
assertEquals(1, tasks.size());
Task task = tasks.get(0);
assertEquals("Ship Order", task.getName());
场景一:
场景二:
场景三:
场景四:
基于事件的网关:
outgoing
顺序流。intermediateCatchEvent
之后。intermediateCatchEvent
连接这种网关必须包含一个ingoing
顺序流。<definitions>
<signal id="alertSignal" name="alert" />
<process id="catchSignal">
<startEvent id="start" />
<sequenceFlow sourceRef="start" targetRef="gw1" />
<eventBasedGateway id="gw1" />
<sequenceFlow sourceRef="gw1" targetRef="signalEvent" />
<sequenceFlow sourceRef="gw1" targetRef="timerEvent" />
<intermediateCatchEvent id="signalEvent" name="Alert">
<signalEventDefinition signalRef="alertSignal" />
</intermediateCatchEvent>
<intermediateCatchEvent id="timerEvent" name="Alert">
<timerEventDefinition>
<timeDuration>PT10M</timeDuration>
</timerEventDefinition>
</intermediateCatchEvent>
<sequenceFlow sourceRef="timerEvent" targetRef="exGw1" />
<sequenceFlow sourceRef="signalEvent" targetRef="task" />
<userTask id="task" name="Handle alert"/>
<exclusiveGateway id="exGw1" />
<sequenceFlow sourceRef="task" targetRef="exGw1" />
<sequenceFlow sourceRef="exGw1" targetRef="end" />
<endEvent id="end" />
</process>
</definitions>
该流程引擎支持下边几种类型的开始事件:
Blank
Timer
Message
Signal
Conditional
异步事件定义:
<startEvent id="startEvent" camunda:asyncBefore="true" />
// 开始事件
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey('invoice');
一个子流程(Subprocess)必须以一个空事件开始。
<endEvent id="end" name="my end event" />
<intermediateThrowEvent id="noneEvent">
<extensionElements>
<camunda:executionListener
class="org.camunda.bpm.engine.test.bpmn.event.IntermediateNoneEventTest$MyExecutionListener"
event="start" />
</extensionElements>
</intermediateThrowEvent>
在BPMN 2.0
中可直接使用messageEventDefinition
元素定义一个消息信息,然后直接使用messageRef
来引用。
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:camunda="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>
您可以在消息定义中直接使用表达式语法:
<message id="newInvoice" name="newInvoiceMessage-${execution.processBusinessKey}" />
消息类的API使用了如下规范:
// correlate the message
MessageCorrelationResult result = runtimeService.createMessageCorrelation("messageName")
.processInstanceBusinessKey("AB-123")
.setVariable("payment_type", "creditCard")
.correlateWithResult();
订阅和触发
ProcessInstance pi = runtimeService.startProcessInstanceByKey("processWaitingInReceiveTask");
EventSubscription subscription = runtimeService.createEventSubscriptionQuery()
.processInstanceId(pi.getId()).eventType("message").singleResult();
runtimeService.messageEventReceived(subscription.getEventName(), subscription.getExecutionId());
下边条件可引起关联消息成功:
读取结果MessageCorrelcationResult
对象:
// 直接调用
List<MessageCorrelationResult> results = runtimeService
.createMessageCorrelation("aMessageName")
.correlateAllWithResult();
// 读取结果
MessageCorrelationResultWithVariables result = runtimeService
.createMessageCorrelation("aMessageName")
.setVariable("name", "value")
.correlateWithResultAndVariables(shouldDeserializeValues);
VariableMap processVariables = result.getVariables();
// 输入变量
List<MessageCorrelationResult> results = runtimeService
.createMessageCorrelation("aMessageName")
.localVariableEquals("localVarName", "localVarValue"))
.correlateAllWithResult();
使用下边API触发消息发送
ProcessInstance startedProcessInstance = runtimeService
.createMessageCorrelation("messageName")
.processInstanceBusinessKey("businessKey")
.setVariable("name", "value")
.correlateStartMessage();
// or
MessageCorrelationResultWithVariables result = runtimeService
.createMessageCorrelation("aMessageName")
.processInstanceBusinessKey("businessKey")
.startMessageOnly()
.setVariable("name", "value")
.correlateWithResultAndVariables(shouldDeserializeValues);
ProcessInstance startedProcessInstance = result.getProcessInstance();
VariableMap processVariables = result.getVariables();
还有几种不同的触发方式:
// 基于消息名称触发
ProcessInstance startProcessInstanceByMessage(String messageName);
ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
ProcessInstance startProcessInstanceByMessage(String messageName,
String businessKey, Map<String, Object> processVariables);
// 附加执行ID,接收消息
void messageEventReceived(String messageName, String executionId);
void messageEventReceived(String messageName, String executionId,
HashMap<String, Object> processVariables);
// 使用Process Definition Query
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.messageEventSubscription("newCallCenterBooking")
.singleResult();
// 执行消息查询
Execution execution = runtimeService.createExecutionQuery()
.messageEventSubscriptionName("paymentReceived")
.processVariableValueEquals("orderId", message.getOrderId())
.singleResult();
开始事件的条件:
ProcessInstance startProcessInstanceByMessage(String messageName);
ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
ProcessInstance startProcessInstanceByMessage(String messageName,
String businessKey, Map<String, Object> processVariables);
下边的API可启动一个流程
如果有多个消息事件,调用:
runtimeService.startProcessInstanceByMessage(...)
。
如果有多个消息事件 + 一个空开始事件,调用:
runtimeService.startProcessInstanceByKey(...)
runtimeService.startProcessInstanceById(...)
启动空事件
如果有多个消息事件 + 无空开始事件,调用:
runtimeService.startProcessInstanceByKey(...)
runtimeService.startProcessInstanceById(...)
抛异常
如果有单个消息开始事件
runtimeService.startProcessInstanceByKey(...)
runtimeService.startProcessInstanceById(...)
使用消息开始事件启动一个新实例
Call Activity
启动,则只有下边条件可支持消息开始事件
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:camunda="http://activiti.org/bpmn"
targetNamespace="Examples"
xmlns:tns="Examples">
<message id="newInvoice" name="newInvoiceMessage" />
<process id="invoiceProcess">
<startEvent id="messageStart" >
<messageEventDefinition messageRef="tns:newInvoice" />
</startEvent>
...
</process>
</definitions>
<intermediateCatchEvent id="message">
<messageEventDefinition messageRef="newCustomerMessage" />
</intermediateCatchEvent>
<intermediateThrowEvent id="message">
<messageEventDefinition camunda:class="org.camunda.bpm.MyMessageServiceDelegate" />
</intermediateThrowEvent>
<endEvent id="end">
<messageEventDefinition camunda:class="org.camunda.bpm.MyMessageServiceDelegate" />
</endEvent>
该事件的行为和服务任务Service Task
行为一致。
如果要使用计时器,必须定义和配置Job Executor
组件。
时间格式,参考:ISO 8601 Durations
<!--执行时间-->
<timerEventDefinition>
<timeDate>2011-03-11T12:13:14Z</timeDate>
</timerEventDefinition>
<!--执行间隔-->
<timerEventDefinition>
<timeDuration>P10D</timeDuration>
</timerEventDefinition>
<!--定时器生命周期-->
<timerEventDefinition>
<timeCycle>R3/PT10H</timeCycle>
</timerEventDefinition>
// 修改时间周期
managementService.setJobDuedate(String jobId, Date newDuedate)
managementService.setJobDuedate(String jobId, Date newDuedate, boolean cascade)
下边片段定义了表达式语法
<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport">
<timerEventDefinition>
<timeDuration>${duration}</timeDuration>
</timerEventDefinition>
</boundaryEvent>
<!--周期定时器-->
<startEvent id="theStart">
<timerEventDefinition>
<timeCycle>R4/2016-03-11T12:13/PT5M</timeCycle>
</timerEventDefinition>
</startEvent>
<!--固定时间执行-->
<startEvent id="theStart">
<timerEventDefinition>
<timeDate>2016-03-11T12:13:14</timeDate>
</timerEventDefinition>
</startEvent>
<intermediateCatchEvent id="timer">
<timerEventDefinition>
<timeDuration>PT5M</timeDuration>
</timerEventDefinition>
</intermediateCatchEvent>
<boundaryEvent id="escalationTimer" cancelActivity="false" />
<timerEventDefinition>
<timeDuration>PT4H</timeDuration>
</timerEventDefinition>
</boundaryEvent>
通常定义错误事件有两种:业务错误和技术错误。
<definitions>
<error id="myError" errorCode="ERROR-OCCURED" name="ERROR-OCCURED"/>
<!-- ... -->
<process>
<!-- ... -->
<endEvent id="myErrorEndEvent">
<errorEventDefinition errorRef="myError" />
</endEvent>
</process>
</definitions>
另一种错误直接引用Java异常定义:
<definitions>
<error id="myException" errorCode="com.company.MyBusinessException"
name="myBusinessException"/>
<!-- ... -->
<process>
<!-- ... -->
<endEvent id="myErrorEndEvent">
<errorEventDefinition errorRef="myException" />
</endEvent>
</process>
</definitions>
您可以使用camunda:errorMessage
扩展定义错误:
<definitions>
<error id="myError" errorCode="ERROR-OCCURED" name="ERROR-OCCURED"
camunda:errorMessage="Something went wrong: ${errorCause}" />
<!-- ... -->
<process>
<!-- ... -->
<endEvent id="myErrorEndEvent">
<errorEventDefinition errorRef="myError" camunda:errorMessageVariable="err"/>
</endEvent>
</process>
</definitions>
直接使用extensionElements
元素扩展异常信息:
<serviceTask id="validateAddressTask"
name="Validate Address"
camunda:type="external"
camunda:topic="AddressValidation" >
<extensionElements>
<camunda:errorEventDefinition id="addressErrorDefinition"
errorRef="addressError"
expression="${externalTask.getErrorDetails().contains('address error found')}" />
</extensionElements>
</serviceTask>
您可以使用如下标签:
errorRef
camunda:errorCodeVariable
camunda:errorMessageVariable
<definitions>
<error id="myException" errorCode="com.company.MyBusinessException" name="myBusinessException"/>
...
<process>
...
<subProcess id="SubProcess_1" triggeredByEvent="true">>
<startEvent id="myErrorStartEvent">
<errorEventDefinition errorRef="myException" camunda:errorCodeVariable="myErrorVariable"
camunda:errorMessageVariable="myErrorMessageVariable" />
</startEvent>
...
</subProcess>
...
</process>
</definitions>
(略)
<definitions>
<error id="myError" errorCode="ERROR-OCCURED" name="name of error"/>
<!-- ... -->
<process>
<!-- ... -->
<subProcess id="mySubProcess">
<!-- ... -->
</subProcess>
<boundaryEvent id="catchError" attachedToRef="mySubProcess">
<errorEventDefinition errorRef="myError" camunda:errorCodeVariable="myErrorVariable"
camunda:errorMessageVariable="myErrorMessageVariable" />
</boundaryEvent>
</process>
</definitions>
Catch / Re-Throw
<definitions>
<escalation id="lateShipment" escalationCode="ORDER-LATE-SHIPMENT" />
<!-- ... -->
<process>
<!-- ... -->
<intermediateThrowEvent id="throwEscalation" name="late shipment">
<escalationEventDefinition escalationRef="lateShipment" />
</intermediateThrowEvent>
<!-- ... -->
</process>
</definitions>
升级开始事件只能用来触发一个子流程:
<subprocess triggeredByEvent="true">
<startEvent id="catchEscalation" isInterrupting="false">
<escalationEventDefinition camunda:escalationCodeVariable="code"/>
</startEvent>
<!-- ... -->
</subprocess>
<boundaryEvent id="catchEscalation" name="late shipment" attachedToRef="productProcurement">
<escalationEventDefinition escalationRef="lateShipment" cancelActivity="false" />
</boundaryEvent>
限制条件
escalationRef
和escalationCode
则升级边界事件不支持<intermediateThrowEvent id="throwEscalation" name="order shipped">
<escalationEventDefinition escalationRef="orderShipped" />
</intermediateThrowEvent>
<endEvent id="throwEscalation" name="late shipment">
<escalationEventDefinition escalationRef="lateShipment" />
</endEvent>
直接使用信号事件
订阅信号事件
<definitions>
<!-- declaration of the signal -->
<signal id="alertSignal" name="alert" />
<process id="catchSignal">
<intermediateThrowEvent id="throwSignalEvent" name="Alert">
<!-- signal event definition -->
<signalEventDefinition signalRef="alertSignal" />
</intermediateThrowEvent>
<!-- ... -->
<intermediateCatchEvent id="catchSignalEvent" name="On Alert">
<!-- signal event definition -->
<signalEventDefinition signalRef="alertSignal" />
</intermediateCatchEvent>
<!-- ... -->
</process>
</definitions>
在定义中使用表达式:
<signal id="alertSignal" name="alert-${execution.processBusinessKey}" />
// 直接使用
// broadcast signal
runtimeService
.createSignalEvent("signalName")
.setVariables(variables)
.send();
// deliver a signal to a single execution
runtimeService
.createSignalEvent("signalName")
.executionId(executionId)
.setVariables(variables)
.send();
// 在 Runtime 中调用
RuntimeService.signalEventReceived(String signalName);
RuntimeService.signalEventReceived(String signalName, String executionId);
List<Execution> executions = runtimeService.createExecutionQuery()
.signalEventSubscriptionName("alert")
.list();
void signalEventReceived(String signalName);
void signalEventReceived(String signalName, Map<String, Object> processVariables);
<startEvent id="signalStart" >
<signalEventDefinition signalRef="alertSignal" />
</startEvent>
<intermediateCatchEvent id="signal">
<signalEventDefinition signalRef="newCustomerSignal" />
</intermediateCatchEvent>
<boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true">
<signalEventDefinition signalRef="alertSignal"/>
</boundaryEvent>
<intermediateThrowEvent id="signal">
<signalEventDefinition signalRef="newCustomerSignal" />
</intermediateThrowEvent>
<!--异步模式-->
<intermediateThrowEvent id="signal">
<signalEventDefinition signalRef="newCustomerSignal" camunda:asyncBefore="true" />
</intermediateThrowEvent>
<endEvent id="signal">
<signalEventDefinition signalRef="newCustomerSignal" />
</endEvent>
基本定义:
<signalEventDefinition signalRef="newCustomerSignal">
<extensionElements>
<camunda:in source="throwingVariableName" target="catchingVariableName" />
</extensionElements>
</signalEventDefinition>
使用camunda:in
标签设置表达式传入变量:
<signalEventDefinition signalRef="newCustomerSignal">
<extensionElements>
<camunda:in sourceExpression="${X + 5}" target="Y" />
</extensionElements>
</signalEventDefinition>
所有流程可使用的变量
<signalEventDefinition signalRef="newCustomerSignal">
<extensionElements>
<camunda:in variables="all" />
</extensionElements>
</signalEventDefinition>
使用local=true
设置本地事件
<signalEventDefinition signalRef="newCustomerSignal">
<extensionElements>
<camunda:in variables="all" local="true" />
</extensionElements>
</signalEventDefinition>
定义High-Scope
变量
<signalEventDefinition signalRef="newCustomerSignal">
<extensionElements>
<camunda:in variables="all" local="true" />
<camunda:in source="X" target="Y" />
<camunda:in sourceExpression="${X + 5}" target="Z" />
</extensionElements>
</signalEventDefinition>
传递业务键值:Business Key
<signalEventDefinition signalRef="newCustomerSignal">
<extensionElements>
<camunda:in businessKey="${execution.processBusinessKey}" />
</extensionElements>
</signalEventDefinition>
<boundaryEvent id="boundary" attachedToRef="transaction" >
<cancelEventDefinition />
</boundaryEvent>
<intermediateThrowEvent id="throwCompensation">
<compensateEventDefinition />
</intermediateThrowEvent>
<intermediateThrowEvent id="throwCompensation">
<compensateEventDefinition activityRef="bookHotel" />
</intermediateThrowEvent>
<endEvent id="throwCompensation">
<compensateEventDefinition />
</endEvent>
<boundaryEvent id="compensateBookHotelEvt" attachedToRef="bookHotel" >
<compensateEventDefinition />
</boundaryEvent>
<association associationDirection="One" id="a1"
sourceRef="compensateBookHotelEvt" targetRef="undoBookHotel" />
<serviceTask id="undoBookHotel" isForCompensation="true" camunda:class="..." />
<subProcess id="compensationEventSubprocess" triggeredByEvent="true">
<startEvent id="compensationStart" >
<compensateEventDefinition />
</startEvent>
<!-- ... -->
</subProcess>
<conditionalEventDefinition>
<condition type="tFormalExpression">${var1 == 1}</condition>
</conditionalEventDefinition>
使用属性camunda:variableName
注入变量:
<conditionalEventDefinition camunda:variableName="var1"
camunda:variableEvents="create, update">
<condition type="tFormalExpression">${var1 == 1}</condition>
</conditionalEventDefinition>
<boundaryEvent id="conditionalEvent" attachedToRef="taskWithCondition" cancelActivity="false">
<conditionalEventDefinition>
<condition type="tFormalExpression">${var1 == 1}</condition>
</conditionalEventDefinition>
</boundaryEvent>
<intermediateCatchEvent id="conditionalEvent">
<conditionalEventDefinition>
<condition type="tFormalExpression">${var1 == 1}</condition>
</conditionalEventDefinition>
</intermediateCatchEvent>
List<ProcessInstance> instances = runtimeService
.createConditionEvaluation()
.setVariable("temperature", 24)
.evaluateStartConditions();
// or
List<ProcessInstance> instances = runtimeService
.createConditionEvaluation()
.setVariables(variableMap)
.evaluateStartConditions();
<startEvent id="conditionalStartEvent">
<conditionalEventDefinition camunda:variableName="temperature">
<condition type="tFormalExpression">${temperature > 20}</condition>
</conditionalEventDefinition>
</startEvent>
事件子流程中使用条件开始事件:
<subProcess id="EventSubProcess" triggeredByEvent="true">
<startEvent id="conditionalStartEvent">
<conditionalEventDefinition>
<condition type="tFormalExpression">${var1 == 1}</condition>
</conditionalEventDefinition>
</startEvent>
</subProcess>
//set variable on process instance
runtimeService.setVariable(processInstance.getId(), "variable", 1);
// 代理类
public class SetVariableDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
execution.setVariable("variable", 1);
}
}
<process id="someProcess">
<!-- ... -->
<intermediateThrowEvent id="IntermediateThrowEvent_1" name="LinkA">
<linkEventDefinition id="LinkEventDefinition_1" name="LinkA"/>
</intermediateThrowEvent>
<intermediateCatchEvent id="IntermediateCatchEvent_1" name="LinkA">
<linkEventDefinition id="LinkEventDefinition_2" name="LinkA"/>
</intermediateCatchEvent>
<!-- ... -->
</process>
<process id="someProcess">
<!-- ... -->
<endEvent id="EndEvent_2" name="Tweet rejected">
<terminateEventDefinition id="TerminateEventDefinition_1"/>
<endEvent>
<!-- ... -->
</process>
上述教程中显示了如何在Camunda中使用BPMN 2.0,仅做枚举,不做详细剖析,详细内容参考: