首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Activiti 5.19 工作流核心:BPMN 2.0 事件詳解與信號/消息/定時器實戰模式

     編輯:Java 綜合教學

Activiti 5.19 工作流核心:BPMN 2.0 事件詳解與信號/消息/定時器實戰模式

BPMN 2.0 標準統一了工作流建模語言,Activiti 作為標準實現之一,提供了豐富的事件類型支撐複雜業務流程。本文聚焦 BPMN 2.0 事件體系,深入解析定時器事件、錯誤事件、信號事件、消息事件四大核心事件類型的配置語法、執行語義與實戰應用模式。

一、事件基礎:Catching vs Throwing

BPMN 事件按行為分為兩類,圖形標識差異在於圓圈內部是否填充:

類型 視覺標識 行為語義 典型用途
Catching (捕獲) 空心圓圈 ⭘ 流程執行到此等待外部觸發條件滿足 啟動事件、中間等待、邊界捕獲
Throwing (拋出) 實心圓圈 ● 流程執行到此主動觸發事件,繼續向後執行 結束事件、中間拋出、邊界拋出

事件定義賦予事件具體語義:無定義的啟動事件不做任何事;添加定時器定義後,流程在指定時間自動啟動。


二、定時器事件:時間驅動的流程控制

適用於啟動事件、中間事件、邊界事件。必須配置以下三種屬性之一:

1. timeDate:固定時間點觸發

ISO 8601 格式:2016-08-23T18:13:00

<timerEventDefinition>
    <timeDate>2016-08-23T18:13:00</timeDate>
</timerEventDefinition>

2. timeDuration:相對時長觸發

ISO 8601 期間格式:P10D(10天)、P1Y3M5DT6H7M30S

<timerEventDefinition>
    <timeDuration>P10D</timeDuration>
</timerEventDefinition>

3. timeCycle:週期性重複觸發

兩種表達式:

  • ISO 8601 週期:R3/PT10H(重複3次,每次間隔10小時)
  • Cron 表達式: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>

拋出該錯誤事件時,流程引擎會尋找匹配的邊界錯誤事件進行捕獲處理。


四、信號事件:廣播式跨流程通信

特性:全局廣播、無具體接收者、作用域預設為整個引擎

1. 信號定義與拋出/捕獲

<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>

2. Java API 拋出信號

// 全局廣播:所有訂閱該信號的執行實例均觸發
runtimeService.signalEventReceived("alertSignal");

// 定向傳遞:僅觸發指定 executionId 的實例
runtimeService.signalEventReceived("alertSignal", executionId);

3. 查詢訂閱者

List<Execution> executions = runtimeService.createExecutionQuery()
    .signalEventSubscriptionName("alertSignal")
    .list();

4. 作用域控制:進程實例級隔離

Activiti 擴展屬性 activiti:scope,默認 global:

<signal id="alertSignal" name="alert" activiti:scope="processInstance" />

設置為 processInstance 後,信號僅在拋出信號的流程實例內傳播,不影響其他實例。

5. 實戰案例:保險規則變更通知

  • 流程 A:規則變更 → 審批 → 同意後拋出 insuranceRuleChanged 信號
  • 流程 B:合同管理節點捕獲信號 → 重新計算保費
  • 避坑:並行網關分支中,錯誤邊界事件拋出信號會廣播到所有實例,需用 signalEventReceived(signal, executionId) 定向傳遞

五、消息事件:點對點有向通信

特性:具名、攜帶內容、單一接收者、類比郵件/消息隊列

1. 消息定義與引用

<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>

2. 消息啟動流程實例

Activiti 不負責接收外部消息(需應用層對接 JMS/HTTP/WebSocket),收到消息後調用:

// 根據消息名稱啟動
ProcessInstance pi = runtimeService.startProcessInstanceByMessage("newInvoiceMessage");

// 攜帶業務鍵與變量
ProcessInstance pi = runtimeService.startProcessInstanceByMessage(
    "newInvoiceMessage", 
    "businessKey-123", 
    Variables.createVariables().putValue("amount", 1000)
);

3. 觸發等待中的消息事件

// 根據 executionId 觸發特定實例
runtimeService.messageEventReceived("paymentMessage", executionId);

// 攜帶變量
runtimeService.messageEventReceived("paymentMessage", executionId, variablesMap);

4. 查詢訂閱者

  • 啟動事件消息:關聯流程定義,用 ProcessDefinitionQuery
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .messageEventSubscription("newCallCenterBooking")
                .singleResult();
  • 中間消息事件:關聯執行實例,用 ExecutionQuery
    Execution execution = runtimeService.createExecutionQuery()
                .messageEventSubscriptionName("paymentReceived")
                .variableValueEquals("orderId", orderId)
                .singleResult();

5. 多啟動事件統一處理模式

一個流程定義可配置多個消息啟動事件,適用於「不同渠道下單但後續處理邏輯相同」場景。


六、事件類型選型決策表

場景 推薦事件類型 關鍵考量
定時批量處理、SLA 超時提醒、週期性報表生成 定時器事件 配置 timeCycle,啟用 asyncExecutor
業務預期內異常流向(駁回、取消、過期) 錯誤事件 配合邊界事件捕獲,區別于 Java 異常
跨多個獨立流程實例的廣播通知(系統公告、配置變更) 信號事件 注意作用域隔離,必要時用 processInstance 級
外部系統回調、異步服務完成通知、雙方協議交互 消息事件 需應用層實現消息接收與投遞,攜帶業務標識

七、最佳實踐提煉

  1. 優先使用設計器:Activiti Modeler/Eclipse Designer 可視化建模,減少手寫 XML 錯誤
  2. 事件定義集中管理:signal/message/error 在 definitions 根節點聲明,避免重複定義
  3. 信號廣播慎用:大規模實例下廣播性能差,優先用消息事件或縮小作用域
  4. 定時器依賴 Job 執行器:生產環境必須配置集群模式下的 Job Executor 避免重複執行
  5. 表達式動態化參數:${variable} 靈活注入,但需確保變量在作用域內可用
  6. 錯誤 vs 異常:Java 異常用 try-catch / 事務回滾;業務錯誤用 BPMN 錯誤事件建模

掌握 BPMN 2.0 事件體系,能讓工作流從簡單的「審批鏈」進化為支撐複雜業務協同的「事件驅動架構」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved