J2EE工作流管理系统jBPM详解(一)
 
2008-11-21 作者:王铁民 来源:51CTO.com
 

一、jBPM入门简介

概述

工作流业务流程管理技术是基于SOA技术实现的一个核心部分。使用工作流能够在软件开发和业务两个层次受益:

1、方便开发

工作流管理系统能够简化企业级软件开发甚至维护。

  • 降低开发风险 - 通过使用状态和动作这样的术语,业务分析师和开发人员使用同一种语言交谈。这样开发人员就不必将用户需求转化成软件设计了。
  • 实现的集中统一 -业务流程经常变化,使用工作流系统的最大好处是:业务流程的实现代码,不再是散落在各种各样的系统中 。
  • 加快应用开发 - 你的软件不用再关注流程的参与者,开发起来更快,代码更容易维护。

2、业务流程管理 (BPM)

在自动化业务流程之前,分析并将它们规格化是一件艰苦但会有很好回报的工作:

  • 提高效率 - 许多流程在自动化过程中会去除一些不必要的步骤较好的流程控制 - 通过标准的工作方法和跟踪审计,提高了业务流程的管理
  • 改进客户服务 - 因为流程的一致性,提高了对客户响应的可预见性
  • 灵活 - 跨越流程的软件控制,使流程可以按照业务的需要重新设计。
  • 业务流程改进 - 对流程的关注,使它们趋向于流畅和简单

但从长远的角度,工作流流程管理技术的研究可为两个阶段进行:

1.目前解决华研今后新项目中复杂业务流程如何使用工作流引擎技术进行实现的问题。

2.上升到面向服务体系架构,实现各个服务之间的业务流程。

jBPM,全称是Java Business Process Management,是一种基于J2EE的轻量级工作流管理系统。jBPM是公开源代码项目,它使用要遵循 Apache License。

jBPM在2004年10月18日,发布了2.0版本,并在同一天加入了JBoss,成为了JBoss企业中间件平台的一个组成部分,它的名称也改成JBoss jBPM。随着jBPM加入JBoss组织,jBPM也将进入一个全新的发展时代,它的前景是十分光明的。

JBoss jBPM 只有最小的倚赖性,它可以很容易的作为java库来使用.当然它也可以用在访问量很大的J2EE 群应用服务器环境中. JBoss jBPM 可以同任何数据库配置可以部署在任何应用服务器上.

jBPM 最大的特色就是它的商务逻辑定义没有采用目前的一些规范,如WfMC XPDL, BPML, ebXML, BPEL4WS等,而是采用了它自己定义的JBoss jBPM Process definition language (jPdl)。jPdl认为一个商务流程可以被看作是一个UML状态图。jPdl就是详细定义了这个状态图的每个部分,如起始、结束状态,状态之间的转换等。

jBPM的另一个特色是它使用Hibernate来管理它的数据库。Hibernate是目前Java领域最好的一种数据持久层解决方案。通过Hibernate,jBPM将数据的管理职能分离出去,自己专注于商务逻辑的处理。(具体选型报告可参考工作流技术选型评估报告)。

本文档主要是工作流研究小组关于开源工作流引擎jbpm的研究成果总结。内容包括工作流研究场景的介绍、jbpm的环境配置,并包括以下六个研究主题:

  • JBPM同开发如何结合,又如何保持独立性;对应用系统的设计实现有什么样的制约
  • 用户/角色如何同应用系统结合,变化又如何处理
  • 流程中每个活动,如何动态指定执行者
  • 类似传阅功能如何实现
  • 子流程如何实现
  • 流程执行步骤耗时阀值和自动提醒设置
  • jBPM当前版本的稳定性评估

术语、定义和缩略语

应用场景

本场景是从房地产营销系统的需求中提取出来的,在房地产项目中,客户选户购房的过程是一个非常典型的工作流场景。我们将这一过程提取出来,作为jbpm技术研究的场景。

在购房过程中,会有以下人员参与。
客户:购房的主体
销售人员:在购房过程中指导看房,购房。
销售经理:确定认购信息。
财务人员:收取定金。
客服人员:打印收据,打印客户认购书。

客户购房的过程可以描述如下。

  • 客户来到售楼中心,销售人员进行接待。
  • 客户向销售人员提供预先申请的服务号。
  • 销售人员确认服务号是否有效,如果无效现场给出一个新的服务号。
  • 销售人员引导客户选房。
  • 客户确定户型,房号。
  • 销售人员录入客户认购资料。
  • 销售人员确认认购资料填写完整。
  • 销售人员将认购资料提交给销售经理审批。
  • 确定是否可以获得优惠,如果客户是一次交清房款,获得0.1%优惠。
  • 交上级经理审批。
  • 销售人员引导客户到财务处交纳定金。
  • 交纳定金后,客服人员打印收据。
  • 客服人员打印认购书。

为了使用研究的场景更有代表性,揉合其他典型的工作流应用场景,将上面的流程作一些删改。

客户认购的流程改为:

  • 客户确定购房,销售人员录入认购资料。
  • 提交认购资料,必须保证录入资料的完整性。
  • 提交审核,按总金额进行分类审核。如果金额小于50万销售经理审核即可,大于50万还要上级经理两人同时审核通过。
  • 审批完成,客户到财务处交纳定金。
  • 客服人员为客户打印收据,打印认购书,认购完成。

上面的流程中一些异常情况(流程中的一些分支),在这里先不作考虑,如,客户在交纳定金之前可以随时放弃认购。

客户的认购要录入的资料内容包括:客户姓名,房号,定金,总金额,流程号等,这里仅选取几个重要的数据作为保存对象。保存录入资料时自动取得一个流程号,任何时候,可以根据此流程号跟踪流程状态,所以在保存认购资料时要记录流程号。

通用的标准规范

jBPM 是个功能全面的Workflow Engine,融合了4大功能:Workflow,BPM,BPEL,PageFlow。它自己有个BPEL扩展,采用jboss Hibernate实现,它使用自定义的自定义标准jpdl,不支持目前公开的工作流(业务流程)标准,如:

  • JCP
  • JSR208 Java Business Integration
  • JSR207 Process Definition for Java
  • OASIS
  • WS-BPEL
  • Workflow Management Coalition(WFMC)
  • WFMC XPDL
  • Business Process Management Initiative (BPMI)
  • BPMN
  • Object Management Group (OMG)
  • State Chart XML (SCXML)

处理测试阶段的JBoss jBPM BPEL扩展准备支持BPEL 1.1标准(非标准组织通过的标准)。

技术方案

由于公司采取的架构是ejb3+tapestry4架构,所以我们的场景实现架构也是基于以上架构进行实现的(tapestry4+ejb3+jbpm3.2),我们所采取的jbpm版本是3.2,这也是目前jbpm最新的版本。这里我们使用jboss作为我们的web服务器

开发环境

这里我们是采用eclipse3.2开发工具进行开发,Tapestry4+ejb3的开发环境配置和以往的项目配置基本保持一致,这里就不再进行详细介绍,关键就是jbpm3.2的配置方法。

我们从jBoss官方网站(http://www.jboss.org)上下载jbpm-jpdl-suite-3.2.GA.zip,最新的版本是3.2.GA,这个包括:

  • jbpm-server , 预先配置的jboss 应用服务器.
  • jbpm-designer , jBPM流程图形化设计器的eclipse 插件 .
  • jbpm-db , jBPM 数据库兼容包 (参看下面).
  • jbpm , 核心jbpm组件包括库和用户手册.
  • jbpm-bpel , JBoss jBPM BPEL 扩展参考.

预配置的JBoss 应用服务器有下列安装组件: 核心jBPM 组件 , 打包作为JBoss服务档案

一个包括所有jBPM 表格的完整数据库 : 默认的 hypersonic 数据库包含所有的jBPM 表格和已经定义的流程.

jBPM 控制台web应用程序 这个可以用来为jBPM管理员.

jBPM调度程序 所有定时器的执行. 调度程序在新手工具箱里配置成了一个servlet.这个Servlet会为产生一个线程来监视每个定时器的执行.

一个流程例子 已经发布进了jBPM 数据库,关于jbpm-jpdl-suite-3.2套件包的具体介绍,可以参考JBoss jBPM Cookbook手册。

JBoss jBPM 是一个Java库. 因此,它可以用在任何java环境比如web 应用程序,Swing应用程序,EJB,Web Service等等,JBoss jBPM 核心组件被打包成一个简单的Java库文件.它依赖你所使用的功能性, 库 jbpm-jpdl.jar及一些相关的第三方的库比如 . hibernate3.2, dom4j 等等

在我们实现场景中。要使用jbpm,我们首先需要将jbpm3.2的包导入我们的项目当中, jbpm3.2的主要包括两个包jbpm-jpdl.jar和jbpm-identity.jar。而jbpm-jpdl.jar是jbpm的核心包,jbpm-identity.jar则是jbpm自带的用户角色权限管理包。我们将这两个包导入我们的项目中。(具体可参考jbpm的用户手册)

在jbpm中,流程的定义主要是编写在xml文件中的,我们需要将具体的业务流程在xml中定义。所以我们需要在项目的根目录上新建一个源目录,这里我们命名为“processes”,在该目录我们可以保存流程定义xml文件。

JBoss jBPM 包括一个图形化的流程设计工具. 这个设计器是用来创作商业流程的,该图形设计器是一个Eclipse插件,图形化设计工具最重要的特性是它同时支持业务分析员和技术开发人员. 这样就可以在业务流程建模和实际执行之间平滑转换。使用该插件你可以通过界面来拖拉描绘你的业务流程,而不需要靠手写编码来设计。该插件位于jbpm-jpdl-suite-3.2.GA.zip中,插件的安装方法可以参考elipse插件的安装方法。安装完毕后,我们下面可以通过该插件新建流程设计文件。

步骤如下:1、在processes目录中右建选择“New”—》“other”

2、选择“Process Definition”,点击“Next”

输入Process name,点击完成。打开设计界面,我们就可以在上面根据我们的业务来设计工作流流程文件。

Jbpm本身包含很多自己的jbpm数据库表,jBPM内部使用hibernate来管理它的数据库,通过Hibernate,jBPM将数据的管理职能分离出去,自己专注于商务逻辑的处理,而且我们可以使jBPM移植在不同的数据库.。我们进行的每一步流程操作都保存在jbpm数据表中,通过调用jbpm提供的接口,我们可以对jBPM数据库进行存储,更新和检索流程信息的服务。这里我们使用Mysql5.0数据库,下面我们在项目中新建一个源目录“config.files”,名字可以任意,在该目录建立hibernate.cfg.xml文件:

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>

<!-- hibernate dialect -->
<!--property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property-->
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>

<!-- JDBC connection properties (begin) ===
<property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="hibernate.connection.url">jdbc:hsqldb:mem:jbpm</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>
==== JDBC connection properties (end) -->

<!-- JDBC connection for MySQL database -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql://localhost/myjbpm
</property>
<property name="connection.username">root</property>
<property name="connection.password">1234</property>

<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>

<property name="hibernate.cache.provider_class">
org.hibernate.cache.HashtableCacheProvider
</property>

<!-- use data source -->
<!-- DataSource properties (begin)
<property name="hibernate.connection.datasource">
java:comp/env/JbpmDS</property>
DataSource properties (end) -->

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>

<!-- JTA transaction properties (begin) ===
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JTATransactionFactory</property>
<property name="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.JBossTransactionManagerLookup</property>
==== JTA transaction properties (end) -->

<!-- CMT transaction properties (begin) ===
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.CMTTransactionFactory</property>
<property name="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.JBossTransactionManagerLookup</property>
==== CMT transaction properties (end) -->

<!-- logging properties (begin) ===
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.use_sql_comments">true</property>
==== logging properties (end) -->

<!-- ############################################ -->
<!-- # mapping files with external dependencies # -->
<!-- ############################################ -->

<!-- following mapping file has a dependendy on   -->
<!-- 'bsh-{version}.jar'.                         -->
<!-- uncomment this if you don't have bsh on your -->
<!-- classpath.  you won't be able to use the     -->
<!-- script element in process definition files   -->
<mapping resource="org/jbpm/graph/action/Script.hbm.xml" />

<!-- following mapping files have a dependendy on  -->
<!-- 'jbpm-identity.jar', mapping files            -->
<!-- of the pluggable jbpm identity component.     -->
<!-- Uncomment the following 3 lines if you        -->
<!-- want to use the jBPM identity mgmgt           -->
<!-- component.                                    -->
<!-- identity mappings (begin) -->
<mapping resource="org/jbpm/identity/User.hbm.xml" />
<mapping resource="org/jbpm/identity/Group.hbm.xml" />
<mapping resource="org/jbpm/identity/Membership.hbm.xml" />
<!-- identity mappings (end) -->

<!-- following mapping files have a dependendy on  -->
<!-- the JCR API                                   -->
<!-- jcr mappings (begin) ===
<mapping resource="org/jbpm/context/exe/variableinstanc
                 /JcrNodeInstance.hbm.xml"/>
==== jcr mappings (end) -->


<!-- ###################### -->
<!-- # jbpm mapping files # -->
<!-- ###################### -->

<!-- hql queries and type defs -->
<mapping resource="org/jbpm/db/hibernate.queries.hbm.xml" />

<!-- graph.def mapping files -->
<mapping
resource="org/jbpm/graph/def/ProcessDefinition.hbm.xml" />
<mapping resource="org/jbpm/graph/def/Node.hbm.xml" />
<mapping resource="org/jbpm/graph/def/Transition.hbm.xml" />
<mapping resource="org/jbpm/graph/def/Event.hbm.xml" />
<mapping resource="org/jbpm/graph/def/Action.hbm.xml" />
<mapping resource="org/jbpm/graph/def/SuperState.hbm.xml" />
<mapping resource="org/jbpm/graph/def/ExceptionHandler.hbm.xml" />
<mapping resource="org/jbpm/instantiation/Delegation.hbm.xml" />

<!-- graph.node mapping files -->
<mapping resource="org/jbpm/graph/node/StartState.hbm.xml" />
<mapping resource="org/jbpm/graph/node/EndState.hbm.xml" />
<mapping resource="org/jbpm/graph/node/ProcessState.hbm.xml" />
<mapping resource="org/jbpm/graph/node/Decision.hbm.xml" />
<mapping resource="org/jbpm/graph/node/Fork.hbm.xml" />
<mapping resource="org/jbpm/graph/node/Join.hbm.xml" />
<mapping resource="org/jbpm/graph/node/State.hbm.xml" />
<mapping resource="org/jbpm/graph/node/TaskNode.hbm.xml" />

<!-- context.def mapping files -->
<mapping
resource="org/jbpm/context/def/ContextDefinition.hbm.xml" />
<mapping resource="org/jbpm/context/def/VariableAccess.hbm.xml" />

<!-- taskmgmt.def mapping files -->
<mapping
resource="org/jbpm/taskmgmt/def/TaskMgmtDefinition.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/def/Swimlane.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/def/Task.hbm.xml" />
<mapping
resource="org/jbpm/taskmgmt/def/TaskController.hbm.xml" />

<!-- module.def mapping files -->
<mapping
resource="org/jbpm/module/def/ModuleDefinition.hbm.xml" />

<!-- bytes mapping files -->
<mapping resource="org/jbpm/bytes/ByteArray.hbm.xml" />

<!-- file.def mapping files -->
<mapping resource="org/jbpm/file/def/FileDefinition.hbm.xml" />

<!-- scheduler.def mapping files -->
<mapping
resource="org/jbpm/scheduler/def/CreateTimerAction.hbm.xml" />
<mapping
resource="org/jbpm/scheduler/def/CancelTimerAction.hbm.xml" />

<!-- graph.exe mapping files -->
<mapping resource="org/jbpm/graph/exe/Comment.hbm.xml" />
<mapping resource="org/jbpm/graph/exe/ProcessInstance.hbm.xml" />
<mapping resource="org/jbpm/graph/exe/Token.hbm.xml" />
<mapping resource="org/jbpm/graph/exe/RuntimeAction.hbm.xml" />

<!-- module.exe mapping files -->
<mapping resource="org/jbpm/module/exe/ModuleInstance.hbm.xml" />

<!-- context.exe mapping files -->
<mapping
resource="org/jbpm/context/exe/ContextInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/TokenVariableMap.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/VariableInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/variableinstance/ByteArrayInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/variableinstance/DateInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/variableinstance/DoubleInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/variableinstance/HibernateLongInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/variableinstance/HibernateStringInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/variableinstance/LongInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/variableinstance/NullInstance.hbm.xml" />
<mapping
resource="org/jbpm/context/exe/variableinstance/StringInstance.hbm.xml" />

<!-- job mapping files -->
<mapping resource="org/jbpm/job/Job.hbm.xml" />
<mapping resource="org/jbpm/job/Timer.hbm.xml" />
<mapping resource="org/jbpm/job/ExecuteNodeJob.hbm.xml" />
<mapping resource="org/jbpm/job/ExecuteActionJob.hbm.xml" />

<!-- taskmgmt.exe mapping files -->
<mapping
resource="org/jbpm/taskmgmt/exe/TaskMgmtInstance.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/exe/TaskInstance.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/exe/PooledActor.hbm.xml" />
<mapping
resource="org/jbpm/taskmgmt/exe/SwimlaneInstance.hbm.xml" />

<!-- logging mapping files -->
<mapping resource="org/jbpm/logging/log/ProcessLog.hbm.xml" />
<mapping resource="org/jbpm/logging/log/MessageLog.hbm.xml" />
<mapping resource="org/jbpm/logging/log/CompositeLog.hbm.xml" />
<mapping resource="org/jbpm/graph/log/ActionLog.hbm.xml" />
<mapping resource="org/jbpm/graph/log/NodeLog.hbm.xml" />
<mapping
resource="org/jbpm/graph/log/ProcessInstanceCreateLog.hbm.xml" />
<mapping
resource="org/jbpm/graph/log/ProcessInstanceEndLog.hbm.xml" />
<mapping resource="org/jbpm/graph/log/ProcessStateLog.hbm.xml" />
<mapping resource="org/jbpm/graph/log/SignalLog.hbm.xml" />
<mapping resource="org/jbpm/graph/log/TokenCreateLog.hbm.xml" />
<mapping resource="org/jbpm/graph/log/TokenEndLog.hbm.xml" />
<mapping resource="org/jbpm/graph/log/TransitionLog.hbm.xml" />
<mapping resource="org/jbpm/context/log/VariableLog.hbm.xml" />
<mapping
resource="org/jbpm/context/log/VariableCreateLog.hbm.xml" />
<mapping
resource="org/jbpm/context/log/VariableDeleteLog.hbm.xml" />
<mapping
resource="org/jbpm/context/log/VariableUpdateLog.hbm.xml" />
<mapping
resource="org/jbpm/context/log/variableinstance/ByteArrayUpdateLog.hbm.xml" />
<mapping
resource="org/jbpm/context/log/variableinstance/DateUpdateLog.hbm.xml" />
<mapping
resource="org/jbpm/context/log/variableinstance/DoubleUpdateLog.hbm.xml" />
<mapping
resource="org/jbpm/context/log/variableinstance/HibernateLongUpdateLog.hbm.xml" />
<mapping
      resource="org/jbpm/context/log/variableinstance/HibernateStringUpdateLog.hbm.xml" />
<mapping
        resource="org/jbpm/context/log/variableinstance/LongUpdateLog.hbm.xml" />
<mapping
        resource="org/jbpm/context/log/variableinstance/StringUpdateLog.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/log/TaskLog.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/log/TaskCreateLog.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/log/TaskAssignLog.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/log/TaskEndLog.hbm.xml" />
<mapping resource="org/jbpm/taskmgmt/log/SwimlaneLog.hbm.xml" />
<mapping
resource="org/jbpm/taskmgmt/log/SwimlaneCreateLog.hbm.xml" />
     <mapping
resource="org/jbpm/taskmgmt/log/SwimlaneAssignLog.hbm.xml" />

</session-factory>
</hibernate-configuration>

我们在web应用项目的web.xml文件中定义JbpmContextFilter过滤类,它用于实现JBPMCONTEXT 的初始化

<filter>
<filter-name>JbpmContextFilter</filter-name>
<filter-class>org.jbpm.web.JbpmContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>JbpmContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

到这里,jbpm的配置已经基本完成,关于jbpm详细资料大家可以参考jbpm用户指南,这里就不多说。


火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。
资源网站: UML软件工程组织