消息事件(Message Event):
- 消息事件是一個引用了被命名的消息的事件
- 一個消息有一個名稱和對應的消息負載
- 與信號不一樣据沈,消息事件始終指向單一的接收人
- 消息支持表達式,例如:<message id="messageId" name="name-${execution.processBusinessKey}" />這樣就會動態(tài)的從流程參數(shù)中去獲取到對應的值,并解析消息名稱
- 消息開始事件名稱不支持表達式拾因,但是子流程的消息開始事件是支持表達式的
一、消息的API(Message Api):
- 1.作為一個內嵌的流程引擎(Camunda engine)壳坪,camunda不關心消息接收的部分识藤。消息接收部分依賴于流程引擎所在的環(huán)境,并且需要平臺特殊活動咳秉,例如:連接到JMS的隊列/主題(Topic),或者一個web服務鸯隅,或者一個rest請求澜建,所以接收消息是用戶需要去實現(xiàn)的部分即:用戶自己實現(xiàn)從哪里接收消息,mq或者web服務或者rest接口蝌以。接到消息后炕舵,你可以選擇關聯(lián)到觸發(fā)一個新的流程實例,或者觸發(fā)一個等待的執(zhí)行(execution)
- 2.使用運行時服務(Runtime Service’s )關聯(lián)消息和流程實例的方法:
????- 流程引擎(Camunda engine)提供了一個基本的關聯(lián)消息和流程實例的機制饼灿,這會通知(signal)一個等待特殊消息的執(zhí)行(execution幕侠,即:消息中間事件),或者用匹配的消息開始事件實例化一個流程碍彭,RuntimeService提供了流式消息管理API - 3.關聯(lián)消息的結果是一個MessageCorrelationResult對象晤硕,不管是一個execution或者是一個processDefinition。如果是一個execution庇忌,則消息關聯(lián)的是一個捕獲消息中間事件(intermediate message catch event)舞箍,如果是一個processDefinition,則消息關聯(lián)的是一個消息開始事件皆疹。如果是execution疏橄,則可以通過result.getExecution(),獲取Execution略就,如果是processDefinition則可以通過result.getProcessInstance()來獲取ProcessInstance捎迫。
- 4.你可以通過messageName和businessKey來直接觸發(fā)關聯(lián),也可以明確的查詢出這個subscription(subscription:大意是消息事件創(chuàng)建的一個event subscription)來進行觸發(fā)
// 通過messageName和businessKey來直接觸發(fā)關聯(lián)(開始一個流程)
MessageCorrelationResult result = runtimeService.createMessageCorrelation("messageName")
.processInstanceBusinessKey("AB-123")
.setVariable("payment_type", "creditCard")
.correlateWithResult();
ProcessInstance pi = runtimeService.startProcessInstanceByKey("processWaitingInReceiveTask");
// 注釋:messageName標識是定義在bpmn流程圖的xml文件中的name屬性中的
// 關聯(lián)成功后只會返回Process Definition或者Execution (Process Instance)中的一個
//明確的查詢出這個subscription(subscription:大意是消息事件創(chuàng)建的一個event subscription表牢,即:觸發(fā)一個消息中間事件)來進行觸發(fā)
EventSubscription subscription = runtimeService.createEventSubscriptionQuery()
.processInstanceId(pi.getId())
.eventType("message")
.singleResult();
runtimeService.messageEventReceived(subscription.getEventName(), subscription.getExecutionId());
- 5.使用一個messageName關聯(lián)一個消息到多個匹配的executions窄绒,觸發(fā)消息中間事件,或者實例化多個流程實例(批量操作):
List<MessageCorrelationResult> results = runtimeService
.createMessageCorrelation("aMessageName")
.correlateAllWithResult();
- 6.在發(fā)起一個流程時崔兴,還可以獲取到流程參數(shù)彰导,通過一個布爾參數(shù)shouldDeserializeValues指定是否獲取
MessageCorrelationResultWithVariables result = runtimeService
.createMessageCorrelation("aMessageName")
.setVariable("name", "value")
.correlateWithResultAndVariables(shouldDeserializeValues);
//流程參數(shù)
VariableMap processVariables = result.getVariables();
- 7.還提供了通過本地執(zhí)行參數(shù)(local execution variables)關聯(lián)消息的能力,所謂local execution variables是指的當前作用域蛔翅,我的理解是當前流程實例,例如當前在子流程里位谋,就使用的子流程的變量山析,不會涉及到父流程的變量
List<MessageCorrelationResult> results = runtimeService
.createMessageCorrelation("aMessageName")
.localVariableEquals("localVarName", "localVarValue"))
.correlateAllWithResult();
- 8.顯示的觸發(fā)一個消息(Explicitly Triggering a Message)
//觸發(fā)一個消息開始事件
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();
//or
ProcessInstance startProcessInstanceByMessage(String messageName);
ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables);
//觸發(fā)消息中間事件
void messageEventReceived(String messageName, String executionId);
void messageEventReceived(String messageName, String executionId, HashMap<String, Object> processVariables);
- 9.查詢消息事件訂閱(Querying for Message Event Subscriptions:在進行中的消息事件的訂閱,在ACT_RU_EVENT_SUBSCR表中):
????- 這個查詢支持消息開始事件和消息中間事件
????- 如果是消息開始事件掏父,這個消息事件的訂閱與一個特殊的流程定義笋轨,這個消息訂閱可以用ProcessDefinitionQuery查詢
//消息開始事件,查詢流程定義信息
Execution execution = runtimeService.createExecutionQuery()
.messageEventSubscriptionName("paymentReceived")
.processVariableValueEquals("orderId", message.getOrderId())
.singleResult();
????- 這個查詢只會返回null或者一個流程定義赊淑,如果流程定義發(fā)布了新的版本翩腐,會返回最新版本的流程定義
????- 如果是消息中間事件,會返回一個特定的execution膏燃,這個消息訂閱可以用ExecutionQuery查詢
Execution execution = runtimeService.createExecutionQuery()
.messageEventSubscriptionName("paymentReceived")
.processVariableValueEquals("orderId", message.getOrderId())
.singleResult();
二、消息開始事件(Message Start Event):
- 消息開始事件可以用作何什,通過一個被命名的消息來開始一個流程實例组哩。這允許我們在一堆的開始事件中選擇正確的開始事件發(fā)起流程
- 當我們部署一個流程定義,且這個流程定義有一個或多個消息開始事件時处渣,我們要注意以下幾方面:
????1.在同一個流程定義中伶贰,不允許存在多個name相同的消息開始事件(例如:離職流程的流程定義中,不允許存在相同name的消息開始事件)
????2.在所有的部署的流程定義中罐栈,消息開始事件的name也必須是唯一(例如:離職流程和轉正流程中黍衙,不允許存在相同name的消息開始事件)
????3.根據(jù)部署的最新版本的流程定義,之前版本的消息訂閱(部署成功的消息訂閱荠诬,即:老版本的流程定義中的消息開始事件會被取消琅翻,不會跟新版本并行監(jiān)聽消息來發(fā)起流程)將會被取消掉,新版本中沒有出現(xiàn)的消息事件也會被取消 - 可以用RuntimeService的下列方法柑贞,通過觸發(fā)消息開始事件來開始一個流程:
ProcessInstance startProcessInstanceByMessage(String messageName);
ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);
ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables);
注釋:
???? 1.messageName是由bpmn的xml文件中的messageEventDefinition元素的messageRef屬性引用的消息元素的name屬性中給出的名稱
???? 2.在啟動流程實例時方椎,需要注意一下幾個問題:
???????? - 消息開始事件只支持最外層的流程,不支持子流程钧嘶,子流程可以用空開始事件
???????? - 如果流程定義有多個消息開始事件棠众,runtimeService.startProcessInstanceByMessage(...)會選擇一個合適的消息開始事件(根據(jù)messageName來確定正常的消息開始事件)
???????? - 如果流程有多個消息開始事件和一個空開始事件,runtimeService.startProcessInstanceByKey(...)和runtimeService.startProcessInstanceById(...)會用空開始事件開始一個流程實例
???????? - 如果流程有多個消息開始事件有决,且沒有空開始事件闸拿,則runtimeService.startProcessInstanceByKey(...)和runtimeService.startProcessInstanceById(...)會拋出異常
???????? - 如果流程只有一個消息開始事件, runtimeService.startProcessInstanceByKey(...)和runtimeService.startProcessInstanceById(...)會通過消息開始事件開始一個流程
???????? - 如果流程是被調用活動開始的书幕,那么消息開始事件只在一下兩種情況下支持:
???????????? 1. 除了消息開始事件之外新荤,流程還有一個空開始事件
???????????? 2.流程只有一個消息開始事件
-
一個流程可以被多個不同的消息事件發(fā)起,這對于那些需要不同的方式發(fā)起流程按咒,卻最終會以統(tǒng)一的方式運行的流程非常有用
三迟隅、消息中間捕獲事件(Message Intermediate Catching Event):
-
當一個流程到達消息中間捕獲事件時但骨,它會等待在這里,直到一個有正確name的消息到達智袭,流程才會繼續(xù)往下走
四奔缠、消息邊界事件(Message Boundary Event):
-
邊界事件是一個捕獲事件,它是依賴一個活動(activity吼野,見上圖2的完成訂單的活動)校哎,這意味著,當這個活動是在運行狀態(tài)下瞳步,這個消息邊界事件在監(jiān)聽著一個被命名的消息闷哆,當消息到達后,有兩種情況单起,這兩種情況取決于于邊界事件的配置(中斷消息邊界事件和不中斷消息邊界事件):
???? 1.中斷消息邊界事件抱怔,以圖2為例:當消息邊界事件接收到消息被觸發(fā)后,完成訂單的活動(activity)被中斷
???? 2.不中斷消息邊界事件:以圖3為例:當不中斷消息邊界事件接收到消息被觸發(fā)后嘀倒,完成訂單的活動和處理訂單取消的活動同時處于running狀態(tài)
五屈留、消息中間拋出事件(Message Intermediate Throwing Event):
-
消息中間拋出事件會向外部服務發(fā)送一個消息,消息中間拋出事件的這個行為跟Service Task類似
六测蘑、消息結束事件(Message End Event):
-
當流程執(zhí)行到消息結束事件時灌危,當前路徑下的執(zhí)行結束,并且會發(fā)送一條消息碳胳,這個發(fā)消息的行為跟Service Task類似