BPMN 2.0 標準統一了工作流建模語言,Activiti 作為標準實現之一,提供了豐富的事件類型支撐複雜業務流程。本文聚焦 BPMN 2.0 事件體系,深入解析定時器事件、錯誤事件、信號事件、消息事件四大核心事件類型的配置語法、執行語義與實戰應用模式。
BPMN 事件按行為分為兩類,圖形標識差異在於圓圈內部是否填充:
| 類型 | 視覺標識 | 行為語義 | 典型用途 |
|---|---|---|---|
| Catching (捕獲) | 空心圓圈 ⭘ | 流程執行到此等待外部觸發條件滿足 | 啟動事件、中間等待、邊界捕獲 |
| Throwing (拋出) | 實心圓圈 ● | 流程執行到此主動觸發事件,繼續向後執行 | 結束事件、中間拋出、邊界拋出 |
事件定義賦予事件具體語義:無定義的啟動事件不做任何事;添加定時器定義後,流程在指定時間自動啟動。
適用於啟動事件、中間事件、邊界事件。必須配置以下三種屬性之一:
ISO 8601 格式:2016-08-23T18:13:00
<timerEventDefinition>
<timeDate>2016-08-23T18:13:00</timeDate>
</timerEventDefinition>
ISO 8601 期間格式:P10D(10天)、P1Y3M5DT6H7M30S
<timerEventDefinition>
<timeDuration>P10D</timeDuration>
</timerEventDefinition>
兩種表達式:
R3/PT10H(重複3次,每次間隔10小時)0 0/5 * * * ?(每5分鐘),首位為秒(非標準 Cron 的分鐘)<!-- ISO 8601 週期,可選 endDate -->
<timerEventDefinition>
<timeCycle activiti:endDate="2016-08-22T16:42:11+00:00">R3/PT10H</timeCycle>
</timerEventDefinition>
<!-- 表達式動態注入 -->
<timerEventDefinition>
<timeCycle>R3/PT10H/${EndDate}</timeCycle>
</timerEventDefinition>
<!-- Cron 表達式 -->
<timerEventDefinition>
<timeCycle>0 0/5 * * * ?</timeCycle>
</timerEventDefinition>
需在 activiti.cfg.xml 啟用異步執行器:
<property name="asyncExecutorActivate" value="true" /> <!-- 或舊版 --> <property name="jobExecutorActivate" value="true" />
<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport">
<timerEventDefinition>
<timeDuration>${duration}</timeDuration> <!-- 從流程變量讀取 -->
</timerEventDefinition>
</boundaryEvent>
關鍵區別:BPMN 錯誤針對業務異常,非 Java 代碼異常。用於建模「訂單取消」、「審批駁回」等業務預期內的異常流向。
<endEvent id="myErrorEndEvent">
<errorEventDefinition errorRef="myError" />
</endEvent>
<!-- 全局定義錯誤 -->
<definitions ...>
<error id="myError" errorCode="ORDER_CANCELLED" />
</definitions>
拋出該錯誤事件時,流程引擎會尋找匹配的邊界錯誤事件進行捕獲處理。
特性:全局廣播、無具體接收者、作用域預設為整個引擎
<definitions ...>
<!-- 全局聲明信號 -->
<signal id="alertSignal" name="alert" />
<process id="throwProcess">
<intermediateThrowEvent id="throwSignalEvent" name="發送告警">
<signalEventDefinition signalRef="alertSignal" />
</intermediateThrowEvent>
</process>
<process id="catchProcess">
<intermediateCatchEvent id="catchSignalEvent" name="接收告警">
<signalEventDefinition signalRef="alertSignal" />
</intermediateCatchEvent>
</process>
</definitions>
// 全局廣播:所有訂閱該信號的執行實例均觸發
runtimeService.signalEventReceived("alertSignal");
// 定向傳遞:僅觸發指定 executionId 的實例
runtimeService.signalEventReceived("alertSignal", executionId);
List<Execution> executions = runtimeService.createExecutionQuery()
.signalEventSubscriptionName("alertSignal")
.list();
Activiti 擴展屬性 activiti:scope,默認 global:
<signal id="alertSignal" name="alert" activiti:scope="processInstance" />
設置為 processInstance 後,信號僅在拋出信號的流程實例內傳播,不影響其他實例。
insuranceRuleChanged 信號signalEventReceived(signal, executionId) 定向傳遞特性:具名、攜帶內容、單一接收者、類比郵件/消息隊列
<definitions ...>
<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>
Activiti 不負責接收外部消息(需應用層對接 JMS/HTTP/WebSocket),收到消息後調用:
// 根據消息名稱啟動
ProcessInstance pi = runtimeService.startProcessInstanceByMessage("newInvoiceMessage");
// 攜帶業務鍵與變量
ProcessInstance pi = runtimeService.startProcessInstanceByMessage(
"newInvoiceMessage",
"businessKey-123",
Variables.createVariables().putValue("amount", 1000)
);
// 根據 executionId 觸發特定實例
runtimeService.messageEventReceived("paymentMessage", executionId);
// 攜帶變量
runtimeService.messageEventReceived("paymentMessage", executionId, variablesMap);
ProcessDefinitionQuery
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
.messageEventSubscription("newCallCenterBooking")
.singleResult();
ExecutionQuery
Execution execution = runtimeService.createExecutionQuery()
.messageEventSubscriptionName("paymentReceived")
.variableValueEquals("orderId", orderId)
.singleResult();
一個流程定義可配置多個消息啟動事件,適用於「不同渠道下單但後續處理邏輯相同」場景。
| 場景 | 推薦事件類型 | 關鍵考量 |
|---|---|---|
| 定時批量處理、SLA 超時提醒、週期性報表生成 | 定時器事件 | 配置 timeCycle,啟用 asyncExecutor |
| 業務預期內異常流向(駁回、取消、過期) | 錯誤事件 | 配合邊界事件捕獲,區別于 Java 異常 |
| 跨多個獨立流程實例的廣播通知(系統公告、配置變更) | 信號事件 | 注意作用域隔離,必要時用 processInstance 級 |
| 外部系統回調、異步服務完成通知、雙方協議交互 | 消息事件 | 需應用層實現消息接收與投遞,攜帶業務標識 |
signal/message/error 在 definitions 根節點聲明,避免重複定義${variable} 靈活注入,但需確保變量在作用域內可用try-catch / 事務回滾;業務錯誤用 BPMN 錯誤事件建模掌握 BPMN 2.0 事件體系,能讓工作流從簡單的「審批鏈」進化為支撐複雜業務協同的「事件驅動架構」。