架构
本章从高层视角简要介绍 CMMN 引擎的内部结构。当然,由于 CMMN 引擎代码是开源的,实际的实现细节可以通过 深入阅读源代码来了解。
如下图所示,CMMN 引擎是 Flowable 引擎生态系统中的引擎之一,其设计方式与其他引擎类似。CMMN 引擎构建在 CMMN 专属服务和共享服务之上:即任务、变量、身份和作业服务,这些服务独立于各引擎。在更低的层次上,实体和数据管理器层负责底层持久化,与其他引擎的实现方式相同。

通过使用共享服务,这也意味着例如来自 BPMN 引擎和 CMMN 引擎的任务会汇集到一起,并可以通过同一套 API 查询和管理。异步执行器也是如此:定时器和异步作业使用相同的逻辑,甚至可以由一个中央执行器统一管理。
共享服务架构还有第二个好处。当各引擎配合使用时(这很常见),引擎会尽可能共享资源,数据库事务将跨越对多个引擎操作的调用,查询缓存是共用的,并且持久化处理独立于引擎本身。
CMMN 引擎的设计遵循与 Flowable 项目中其他引擎相同的原则。下图给出了使用 CMMN 引擎时所涉及的各个组件的高层概览:

从高层视角来看:
- 一个 CmmnEngine 实例由 CmmnEngineConfiguration 创建。该配 置实例可以通过配置文件创建,也可以编程方式创建。
- CmmnEngine 以服务的形式提供对 Flowable CMMN API 的访问:CmmnRepositoryService、CmmnRuntimeService、CmmnTaskService、CmmnHistoryService、CmmnManagementService。这些服务的命名和职责与其他引擎类似。
- 每个 API 方法都会被转换为一个 Command 实例。该 Command 实例被传递给 CommandExecutor,由其让该命令经过一摞 CommandInterceptor。这些拦截器承担各种职责,包括处理事务。
- 最终,Command 通常(除非它是纯粹的数据修改 Command)会在 CmmnEngineAgenda 上规划一个 CmmnOperation。
- 操作将从 CmmnEngineAgenda 中不断取出,直到没有剩余操作为止。通常,一个操作会在其逻辑中规划新的操作。
- 操作中的逻辑会调用更底层的服务和/或实体管理器。
BPMN 引擎与 CMMN 引擎之间的一大区别在于,BPMN 引擎通常是"本地"的:引擎查看当前状态,检查流程前方是什么,然后继续执行(当然这是一种简化,有许多操作并不适用,但从概念上做区分时,这样说是对的)。CMMN 引擎的工作方式则不同:在 CMMN 中,数据扮演着重要角色,数据的变化可以触发用例定义中各处的许多事情。正因如此,每当发生变化时,EvaluateCriteriaOperation 都会被频繁规划和执行。当引擎检测到重复或无用的求值时,会对这些求值进行优化。
CMMN 引擎工作机制的核心是计划项实例的概念,它表示用例中 当前哪些 计划项 处于 活动 状态以及它们各自的状态。与 BPMN 截然不同的是,CMMN 为计划项定义了严格的状态生命周期。这体现在 CmmnRuntimeService 的方法、查询 API 以及 PlanItemInstance 对象的数据字段中。
agenda 的工作方式、操作以及计划项实例的处理方式,可以通过将 agenda 包的日志级别设置为 debug 来查看。例如,使用 log4j 时:
log4j.logger.org.flowable.cmmn.engine.impl.agenda=DEBUG
这将产生类似如下的日志:
Planned [Init Plan Model] initializing plan model for case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122
Planned [Change PlanItem state] Task A (id: planItemTaskA), new state: [available] with transition [create]
Planned [Change PlanItem state] PlanItem Milestone One (id: planItemMileStoneOne), new state: [available] with transition [create]
Planned [Change PlanItem state] Task B (id: planItemTaskB), new state: [available] with transition [create]
Planned [Change PlanItem state] PlanItem Milestone Two (id: planItemMileStoneTwo), new state: [available] with transition [create]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'create' having fired for plan item planItemTaskA (Task A)
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'create' having fired for plan item planItemMileStoneOne (PlanItem Milestone One)
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'create' having fired for plan item planItemTaskB (Task B)
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'create' having fired for plan item planItemMileStoneTwo (PlanItem Milestone Two)
Planned [Activate PlanItem] Task A (planItemTaskA)
Planned [Change PlanItem state] Task A (id: planItemTaskA), new state: [active] with transition [start]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'start' having fired for plan item planItemTaskA (Task A)
Planned [Change PlanItem state] Task A (id: planItemTaskA), new state: [completed] with transition [complete]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'complete' having fired for plan item planItemTaskA (Task A)
Planned [Activate PlanItem] PlanItem Milestone One (planItemMileStoneOne)
Planned [Change PlanItem state] PlanItem Milestone One (id: planItemMileStoneOne), new state: [active] with transition [start]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'start' having fired for plan item planItemMileStoneOne (PlanItem Milestone One)
Planned [Change PlanItem state] PlanItem Milestone One (id: planItemMileStoneOne), new state: [completed] with transition [occur]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'occur' having fired for plan item planItemMileStoneOne (PlanItem Milestone One)
Planned [Activate PlanItem] Task B (planItemTaskB)
Planned [Change PlanItem state] Task B (id: planItemTaskB), new state: [active] with transition [start]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'start' having fired for plan item planItemTaskB (Task B)
Planned [Change PlanItem state] Task B (id: planItemTaskB), new state: [completed] with transition [complete]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'complete' having fired for plan item planItemTaskB (Task B)
Planned [Activate PlanItem] PlanItem Milestone Two (planItemMileStoneTwo)
Planned [Change PlanItem state] PlanItem Milestone Two (id: planItemMileStoneTwo), new state: [active] with transition [start]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'start' having fired for plan item planItemMileStoneTwo (PlanItem Milestone Two)
Planned [Change PlanItem state] PlanItem Milestone Two (id: planItemMileStoneTwo), new state: [completed] with transition [occur]
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'occur' having fired for plan item planItemMileStoneTwo (PlanItem Milestone Two)
Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122
No active plan items found for plan model, completing case instance
Planned [Complete case instance] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122