JBPM是一个优秀的开源工作流框架,核心引擎算法源自PetriNet理论,并深度了集成了Hibernate作为引擎的持久框架。
2006年底,我开始关注JBPM,并准备作实际应用,但是当时关于JBPM的中文资料比较少,于是打算翻译JBPM官方的user guide,翻译初稿在07年上半年完成,对应的版本是V3.1.2,打算在年底利用假期完善后发出来。不过JBPM后来发布了3.2版,其文档也做了相应更新,增加了一些章节,后来工作较忙,没有继续翻译,于是也就一直没有发布。
后续JBPM又发布了3.3版,不过文档并没有更新,仍然采用3.2.3的版本,虽然小版本变化不大,但是这样的做法还是不值得提倡。可以说,,缺少优秀、全面的文档,一直是包括JBPM在内的,不少开源框架的通病;而像Spring、Hibernate这样框架能够成为主流,跟丰富的配套文档、教程、以及市售的铺天盖地的书籍是分不开的。虽然JBPM应用广泛,但文档太少、市场上相关书籍缺失,是限制其继续向前发展的一个不小的障碍。在翻译JBPM文档的同时,我也对其源代码进行了分析,其中就发现有一些功能,代码里已经实现,但文档中却并未提及。
2009年7月,JBPM正式发布了的4.0,与3.X相比,整个项目几乎重写:新的流程定义语言、新的引擎实现、新颖的PVM概念、新的配置方式、全新的开发接口、全新的数据库结构。。。。。。放眼看去,几乎JBPM4与JBPM3压根就没什么关系。另外,文档方面似乎也终于得到了更大的支持,新的官方文档分成了两部分:userguide和devguide,前者关注如何直接上手、接口使用以及流程开发,后者关注对整个架构的设计、更高级复杂的扩展开发。
在8月发布的最新4.1版的devguide里,说到了开发JBPM4的两个目标:
1、 改进可支持性:通过持续集成,对所支持的产品环境、配置提供更好、更长期的支持保证。
2、 降低门槛,提升应用率:区分公共基础型应用和高级定制化应用两种应用模式,让前者上手更快,后者也能减少开发难度。
其实,如果从这两个目的出发,可以发现,JBPM4的变化的确是遵从了这两点,而且进一步深入的分析可以得出这样的结论:尽管整个项目几乎重写,但JBPM的核心机制没有变,即本质未变。下面是devguide中列出的JBPM3与JBPM4的一些变更对照表。
通用名称的变化
JBPM3 | JBPM4 | 备注 |
Node(节点) | Activity(活动) | 根执行(root execution)和流程实例(proces instance)已经是同一个对象了;而在JBPM3里,在流程实例里有一个指向根令牌(root token)的指针。而且,跟JBPM3不同的是,即使逻辑上只有一条执行路径,在JBPM4中,该执行也可以创建一个子执行,并把自己停下来,而让子执行继续。 |
Token(令牌) | Execution(执行) | |
Action(动作) | EventListener(事件监听器) |
JPDL XML的变化
JBPM3 | JBPM4 |
process-defintion | process |
event type=”...” | on event=”...” |
action | event-listener |
node | custom |
process-state | sub-process |
super-state | group(尚在考虑) |
(事件机制的)默认变化
JBPM3 | JBPM4 |
默认情况下,事件传播会触发外部流程元素的动作 | 默认情况下,事件传播只调用在该元素上订阅了的事件监听器,而不会调用外部元素的监听器 |
从这些变更表中,再结合新的JBPM4.1发布包的内容,可以发现,从JBPM3到JBPM4,真正的变化仅仅是:
1、 流程定义语言的模型没有改变,只是部分元素的命名发生变化
2、 流程执行引擎的算法没有改变,只是对原有引擎进行了优化,去掉了冗余的root token。JBPM4出来后,包括在JavaEye里,有不少的文档探讨了JBPM引擎的变化,有的文章分析说其核心引擎的调度机制完全不同了,这是不对的,因为还是Token机制,只是换了个名字(Execution),加上一定的优化(或称简化)。
3、 流程引擎的事件机制没有改变,只是改变了默认的事件触发范围
4、 整个数据库结构完全改变,甚至前缀变成了JBPM4,目的是希望能够跟JBPM3的表不发生冲突,甚至能够两个版本并行运行。其实数据库结构的巨大变化,是第2点变化、以及其他冗余消除的自然结果
5、 接口的变化,文档的调整和重写,只是为了更好的针对公共普通型应用和高级定制型应用,降低二者的开发难度。
这里提到的第2点和第4点,我有深刻的体会,因为在当时应用JBPM3的过程中,在分析JBPM3引擎的时候,也逐渐意识到其引擎存在的几个类似问题:
1、 root token其实是冗余,完全可以合并到流程实例里
2、 module instance 也是冗余的
3、 流程定义相关的表也是冗余的
4、 没有历史表
5、 。。。