J2EE工作流管理系统jBPM详解

altanxiang 贡献于2011-04-06

作者 walkinnet  创建于2011-04-03 09:25:00   修改者Anxiang  修改于2011-04-03 09:25:00字数26769

文档摘要:工作流业务流程管理技术是基于SOA技术实现的一个核心部分。使用工作流能够在软件开发和业务两个层次受益。jBPM,全称是Java Business Process Management,是一种基于J2EE的轻量级工作流管理系统。jBPM是公开源代码项目,它使用要遵循Apache License。jBPM在2004年10月18日,发布了2.0版本,并在同一天加入了JBoss,成为了JBoss企业中间件平台的一个组成部分,它的名称也改成JBossjBPM.随着jBPM加入JBoss组织,jBPM也将进入一个全新的发展时代,它的前景是十分光明的。JBossjBPM只有最小的倚赖性,它可以很容易的作为java库来使用。
关键词:

J2EE工作流管理系统jBPM详解(一) 一、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 (SCX ML) 处理测试阶段的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用户指南,这里就不多说。 子流程的使用 成果介绍 详细阐述开发成果 评审标准:清楚介绍开发成果 当一个流程的业务逻辑非常复杂的时候,可以考虑使用子流程。子流程和主流程是相对独立的。 设计思路 描述主要的设计思路,开发方法以及技术要点 评审标准:清晰表达设计思路和技术要点 在jbpm中,我们可以将一个复杂的业务流程文件根据业务逻辑的不同划分为父流程和子流程,这样一方面可以令我们的流程定义文件不会设计得太臃肿,二来可以方便我们将来的维护,只对需要修改的流程进行修改,而不影响其他流程。 如何使用 阐述如何结合项目需要应用成果进行开发。这部分需要详细描述,让其他开发人员按照此成果报告,能够进行一般简单的开发,具有较强的可操作性。 评审标准:开发人员按此使用说明基本能应用成果进行开发 这里我们介绍下关于jbpm子流程的使用,这里我们定义两个流程定义xml文件,一个是父流程定义文件,一个是子流程定义文件。这里我想当执行完Payfirst任务的时候,jbpm流程能自动去我的子流程文件中去执行那边定义的任务。 这里是父流程processdefinition.xml <?xml version="1.0" encoding="UTF-8"?> <process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="myapp"> 。。。。。。 <task-node name="PayFirst"> <task name="PayFirstTask" swimlane="finance"></task> <transition name="get house contract" to="subprocess"> <action name="action" class="com.myapp.action.MessageActionHandler"> <message> Has pay first bulk of money. Print constract now! </message> </action> </transition> </task-node> <process-state name="subprocess"> <sub-process name="subprocessdefinition"/> <transition to="end"></transition> </process-state> <task-node name="pass round for perusal" signal="last-wait" create-tasks="false"> <task name="perusal"> <assignment actor-id="#{processStarter}"> </assignment> </task> <event type="node-enter"> <action name="createInstance" class="com.myapp.action.CreateTaskInstanceAction"></action> </event> <transition name="backto" to="OnePersonAudit"> </transition> </task-node> </process-definition> 可以看到,上面我们使用到了,在jbpm中,process-state标签代表的是引用子流程。这里我们接着定义子流程文件。 子流程subprocessdefinition定义文件 <?xml version="1.0" encoding="UTF-8"?> <process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="subprocessdefinition"> <swimlane name="service"> <assignment actor-id="service1" /> </swimlane> <start-state name="subStart"> <transition to="PrintContract"></transition> </start-state> <task-node name="PrintContract"> <task name="PrintContractTask" swimlane="service"></task> <transition name="PrintContract" to="end"> <action name="action" class="com.myapp.action.MessageActionHandler"> <message>Finish the process instance now.</message> </action> </transition> </task-node> <end-state name="end"></end-state> </process-definition> 示例实现 结合项目需要实现,采用开发成果开发一个简单应用示例。可以链接到其它文档,如示例实现的项目工程 评审标准:能简单展示开发成果的开发应用 上面我们定义了两个XML文件,一个是父流程,一个是子流程。下面我们说下如何使用这两个文件。首先我们要先部署这两个文件,使用子流程要注意,部署的时候一定要先部署子流程,然后在部署父流程。 ProcessDefinition subProcess = ProcessDefinition.parseXmlResource ("subprocessdefinition/processdefinition.xml"); jbpmContext.deployProcessDefinition(subProcess); ProcessDefinition processDefinition = ProcessDefinition. parseXmlResource("processdefinition.xml"); jbpmContext.deployProcessDefinition(processDefinition); 部署完后,jbpm会将这两个流程定义文件保存在jbpm_processinstance表中,在调用中,与单个流程文件调用没有任何区别,我们调用PrintContract 任务的end()方法,jbpm会根据的流程文件,自动找到子流程文件所定义的任务进行执行。 使用规范 描述使用该技术的规范(如接口设计、接口实现、框架设计、数据结构设计等)、约定、约束等 评审标准:清晰、详细描述出其应用规范 注意事项 描述配置、开发等需要注意的问题,包括各种关键点和难点。可逐步补充 评审标准:开发过程中遇到的关于应用开发成果开发的问题,大部分都可以从这里找到答案 使用子流程要注意: 要先部署子流程,然后再部署主流程,否则,主流成执行的时候会报找不到子流程的异常 直接查看jbpm_Token或者jbpm_log无法找到流程间的关系,需要查看jbpm_processinstance表,才能找到父流程,因为 Token在离开process state的时候就会删除subprocessid,直接看jbpm_log也无法看出两个token之间的关系。 应用系统与jBPM的结合 成果介绍 在实际开发使用jBPM,可以采用jBPM系统与业务系统完全分离的策略。jBPM系统只负责流程的监控和执行,业务的重心仍然是实际业务需求。 设计思路 客户端访问系统时,一切业务相关的操作在业务系统中实现,需要流程监控的业务在jBPM流程系统中建立相关流程,提供相关流程的监控和执行接口,客户端可以通过这些接口对流程进行操作。 启动一个流程实例时,首先访问流程系统,取得一个新的流程实例ID。在业务系统中保存这个ID。 在进行流程监控和执行时,根据这个ID对流程实例进行操作。 如何使用 以上面购房流程为例说明,将客户购房过程在一个Order中进行处理。 客户登记看房,启动一个流程实例,取得流程ID,保存在Order中 销售人员,销售经理,财务人员,都可以通过流程系统提供的API查找当前任务,执行任务时,一方面执行流程,一方面修改Order记录。 示例实现 Order要记录流程ID。 public class Order implements Serializable { private Long id; private Long processId; } 流程和业务系统的接口为OrderManager 和BpmManager。 客户看房登录时先启动一个流程。 BpmManager bpmManger=...; Long processId=bpmManager.createProcess(); Order order=new Order(); order.setProcessId(processId); session.save(order); 在后面的步骤中,可以根据Order的processId取得流程ID,执行流程任务。 bpmManager.executeProcessTask(); ...... session.update(order); ...... 注意事项 应用系统中用户角色如何与jBPM结合 成果介绍 应用系统中的用户应该与jBPM流程系统中一致,必须统一起来才能使用。一方面可以采用用户帐号同步的策略,从业务系统复制必要的用户信息到jBPM流程系统中,另一方面可以使用共用用户账号的策略,保持最基本的用户账号独立性,业务系统从最基本的用户账号上扩展用户信息。 设计思路 由于两个系统中用户在需求上有一定的差别,得益Hibernate的映射机制,可以使用一个用户账号表,不同映射文件,保持系统的相对独立性。 如何使用 jBPM中用户是由identity模块提供,在实际开发中,可以以jBPM中提供的用户表为基础,应用系统的较详细的用户信息在上面扩展。 也可以建立一个基础的用户帐号,jBPM中的用户与应用系统中的用户在它的基础上扩展。 示例实现 jBPM中User提供了几最基本的字段。 public class User extends Entity implements Principal { private static final long serialVersionUID = 1L; protected String password = null; protected String email = null; protected Set memberships = null; public User() { } public User(String name) { super(name); } } Hibernate映射文件内容为: <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping auto-import="false" default-access="field"> <class name="org.jbpm.identity.User" table="JBPM_ID_USER" discriminator-value="U"> <id name="id" column="ID_"><generator class="native" /></id> <discriminator type="char" column="CLASS_"/> <property name="name" column="NAME_"/> <property name="email" column="EMAIL_"/> <property name="password" column="PASSWORD_"/> <set name="memberships" cascade="all"> <key column="USER_" /> <one-to-many class="org.jbpm.identity.Membership" /> </set> <set name="permissions" cascade="all" table="JBPM_ID_PERMISSIONS"> <key column="ENTITY_" foreign-key="none" /> <element type="org.jbpm.identity.hibernate.PermissionUserType"> <column name="CLASS_"/> <column name="NAME_"/> <column name="ACTION_"/> </element> </set> </class> </hibernate-mapping> 这里,应用系统用户为CustomUser,这里采用从jBPM中的User中继承的策略,它多出一个字段carId。 public class CustomUser extends User { private String cardId; public String getCardId() { return cardId; } public void setCardId(String cardId) { this.cardId = cardId; } } 映射文件为: <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping auto-import="false" default-access="field"> <subclass name="com.sample.model.CustomUser" extends="org.jbpm.identity.User" discriminator-value="U"> <join table="CUSTOM_USER"> <key column="ID_"></key> <property name="cardId" column="CARDID_" /> </join> </subclass> </hibernate-mapping> 这里,CustomUser是从jBPM中的User继承的。 jBPM当前版本的稳定性评估 成果介绍 通过官方jbpmRoadMap以及jbpm jira上面所写的计划,得出目前jbpm的版本更新速度将会比较频繁,计划上说将在今年年底完成jbpm4.0,目前版本已经更新到jb pm3.2.1版本,而且从jira上发现jbpm3.3的版本也在快速开发中。而且从jira上看,目前版本升级主要是bug的修改和功能的完善。 流程执行步骤耗时阀值和自动提醒设置 成果介绍 Jbpm内置调度功能, jbpm的调度部分分为2块,timer主要是流程设计人员的工作,将timer放置到流程中;scheduler是jbpm自己维护的,我们只需要在后台进行调用即可。 设计思路 流程执行可以建立或删除定时器. 定时器存放在一个timer store里. 当一个定时器的运行必须先从timer store里面取得并且在根据指定的时间来启动该定时器 Jbpm时间管理思路整体来说实现的非常清晰: 1、引擎解析流程定义xml时,给相应的事件挂接上create-timer 和 cancel-timer动作 2、流程实例实际运转时,create-timer动作在相应事件触发时执行 3、create-timer在job表里插入相应时间job记录,给该job记录附上计算完毕的执行时间 4、JobExecutorServlet在后台启动一到多个JobExecutorThread线程 5、JobExecutorThread线程不停的每隔一段时间对job表扫描一次,找出需要执行的job记录,执行之 6、只执行一次的job记录,执行完毕后删除之;重复执行的job记录,写入新的执行时间,更新之 7、相应事件触发cancel-timer动作,将对应job记录从job表里删除 如何使用 jBPM通过定时器(timer)实现日程调度。在node中加入timer元素,即可实现基于定时器的节点执行监控,实现自动提醒功能。 jbpm提供了2种调用scheduler的方法: 一种是用在web应用的,采用org.jbpm.scheduler.impl.SchedulerServlet,具体的方法这个类的javadoc有很好的示例,我们只需在web.xml中加载它就行了; 另一种是针对的c-s程序,jbpm提供了一个很好的示例 org.jbpm.scheduler.impl.SchedulerMain,我们可以参照它编写我们自己的Scheduler。 实例实现 最容易的方法指定一个定时器是在节点里加入定时器元素. 运用action的timer的例子 <state name='catch crooks'> <timer name='reminder' duedate='3 business hours' repeat='10 business minutes' transition='time-out-transition' > <action class='the-remainder-action-class-name' /> timer> state> 运用script的timer的例子 <state name='catch crooks'> <timer name='reminder' duedate='3 business hours' repeat='10 business minutes' transition='time-out-transition' > <script>System.out.println(new Date())script> timer> state> 在上例中,一旦流程实例运行进入state 'catch crooks',定时器reminder即被创建。该定时器延迟3 business hours开始执行动作,每10 business minutes重复执行一次,到期后马上执行action类中的Java代码,然后实施time-out-transition(或script打印时间)迁移。 通过在事件的action中加入create-timer和cancel-timer动作,可以分别实现事件对定时器的创建和取消。 定时器timer可以被用于decision fork join node process-state state super-state task-node等节点,可以设置开始时间duedate和频率repeat,定时器动作可以是所支持的任何动作元素,如action或script,会运行我们设置的动作。定时器通过动作创建和取消,有两个动作元素create-timer和cancel-timer。事实上,默认的定时器元素只是create-timer动作依附于node-enter事件、cancel-timer动作依附于node-leave事件的一个简略表示。 说说整个过程: 1、令牌进入节点catch crooks 2、timer被触发(实际这时是在执行create-timer动作) 3、3 business hours后 timer 事件触发 4、定义的action被执行 5、令牌顺着time-out-transition路径离开catch crooks节点 6、cancel-timer动作被执行即timer终止(没有给repeat的机会) 另注: 运用timer要先启动scheduler,如果是web项目则只要在web.xml中配置JbpmThreadsServlet,这样在项目启动后会自动开启scheduler。 JbpmThreadsServlet配置如下:  <!-- JbpmThreadsServlet --> <servlet> <servlet-name>JbpmThreadsServletservlet-name> <servlet-class>org.jbpm.web.JbpmThreadsServletservlet-class> <load-on-startup>1load-on-startup> servlet> <servlet-mapping> <servlet-name>JbpmThreadsServletservlet-name> <url-pattern>/threadsurl-pattern> servlet-mapping> 注意事项 对time节点来说 name、repeat、transition都是可选属性。对一个流程定义来说,每一个time节点的name必须唯一,如果你不定义name属性,引擎会默认把node节点的name赋给timer。在上面这个例子里,如果你不定义timer节点的name,则它的name就会是catch crooks。说说repeat属性,如果你不定义它,则timer就会只执行一次动作不会重复执行。transition属性,如果定义了这个属性,流程令牌会在timer执行动作完毕后,顺着这个路径离开node节点。所以在上面这个例子里,尽管定义了repeat属性,action还是会只执行一次。 action节点,可选,即timer节点在时间到时执行的动作,可以是任意action类型,包括script。注意与时间有关的两种action类型:create-timer 和 cancel-timer。其实一个timer节点在被引擎解释时就是被分解为create-timer 和 cancel-timer两个action,create-timer挂接到node-enter事件中,cancel-timer挂接到node- leave事件中。action节点最多只可以挂一个。 传阅功能的实现 成果介绍 传阅功能是管理系统中比较常见的一个功能,这里使用jbpm实现该功能。 设计思路 这里通过使用jbpm的transition来实现传阅功能。 如何使用 关于jbpm的transition使用很简单,大家可以参考jbpm用户指南 示例实现 <task-node name="Coding"> <task name="Coding" swimlane="programmer"/> <transition name="to_CodeReview" to="Code Review"> </transition> <transition name="to_IntegratedTest" to="IntegratedTest"> </transition> </task-node> <task-node name="Code Review"> <task name="Review Code" swimlane="manager"/> </task> <transition name="to_Coding" to="Coding"></transition> </task-node> 上面是一个“代码检查”的类似传阅的流程,程序员编写完代码之后需要传给manager进行代码审查,manager审查完毕需要发回给程序员。 动态指定执行者 成果介绍 上面讲了传阅功能的实现,但大家可以发现,上面的例子只能传阅给流程定义xml文件上面指定的人阅读,即不能是吸纳动态指定传阅。如果不能动态指定执行者,则上面的实现意义不大,在实际操作中,很多操作都充满了不确定性,即可能执行者会经常改变。这里我们介绍如何给任务动态指定执行者。 设计思路 这里我们是通过jbpm的ActionHandler操作动态指定执行者的操作,当进入该任务节点的时候,我们可以通过为该任务指定一个action操作,该操作根据业务规则进行任务执行者的动态指定。 如何使用 我们可以在一个任务task节点使用assignment标签指定运行该任务的执行者,如果没指定的人则不能执行该任务,另外我们也可以通过action操作来在程序中动态设置assignment中的执行人来实现,这里可以是一个或多个执行人。 示例实现 首先我们将流程在processdefinition.xml定义,示例如下: <?xml version="1.0" encoding="UTF-8"?> <process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="myapp"> ... ... <task-node name="OnePersonAudit"> <task name="OnePersonAuditTask" swimlane="manager"> <controller> <variable name="pass" access="read,write,required"></variable> </controller> </task> <!-- event type="node-leave"> <action name="createInstance" class="com.myapp.action.CreateTaskInstanceAction"> </action> </event--> <transition name="OnePersonAduit" to="IsAgreeAduit" /> <transition name="perusaltoone" to="pass round for perusal"></transition> </task-node> <task-node name="pass round for perusal" signal="last-wait" create-tasks="false"> <task name="perusal"> <assignment actor-id="#{processStarter}"></assignment> </task> <event type="node-enter"> <action name="createInstance" class="com.myapp.action.CreateTaskInstanceAction"> </action> </event> <transition name="backto" to="OnePersonAudit"></transition> </task-node> </process-definition> 上面我们有个任务OnePersonAudit,里面有个transition为perusaltoone,它指向任务pass round for perusal,这里是多人传阅的一个流程,在pass round for perusal任务节点中我们使用来指定该任务的执行者, 我们还在该任务中使用了 <event type="node-enter"> <action name="createInstance" class="com.myapp.action.CreateTaskInstanceAction"></action> </event> 事件类型“node-enter”表示当进入该任务时执行CreateTaskInstanceAction类的操作,我们在该类中动态设定该任务的执行者 CreateTaskInstanceAction的代码如下: public class CreateTaskInstanceAction implements ActionHandler { public void execute(ExecutionContext executionContext) throws Exception { // TODO Auto-generated method stub System.out.println("************************************"); System.out.println( " CreateTaskInstanceAction " ); System.out.println("************************************"); Token token = executionContext.getToken(); TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance(); TaskNode taskNode = (TaskNode) executionContext.getNode(); Task task= taskNode.getTask("perusal"); tmi.createTaskInstance(task, token).setActorId("mytest1"); tmi.createTaskInstance(task, token).setActorId("mytest2"); tmi.createTaskInstance(task, token).setActorId("mytest3"); } } 与SSH框架整合 SSH(Struts+Spring+Hibernate)是一种流行的web开发框架。在SSH使用是jBPM,可以考虑使用springmodules的提供的集成方案,在类的管理上会带来一些便利。 在Spring配置文件中声明jbpm使用。 <!-- jBPM Configuration --> <bean id="jbpmConfiguration" class="org.springmodules.workflow .jbpm31.LocalJbpmConfigurationFactoryBean"> <!-- pass in existing sessionFactory --> <property name="sessionFactory" ref="sessionFactory" /> <property name="configuration" value="classpath:/org/appfuse/jbpm/jbpm.cfg.xml" /> <property name="processDefinitions"> <list> <ref local="testProcess" /> </list> </property> <!--property name="createSchema" value="true" /--> </bean> <bean id="testProcess" class="org.springmodules.workflow.jbpm31 .definition.ProcessDefinitionFactoryBean"> <property name="definitionLocation" value="classpath:org/appfuse/jbpm/process/testprocess.xml" /> </bean> <bean id="jbpmTemplate" class="org.springmodules.workflow.jbpm31.JbpmTemplate"> <constructor-arg index="0" ref="jbpmConfiguration" /> <constructor-arg index="1" ref="testProcess" /> </bean> jbpmConfigration依赖的sessionFactory使用SSH的中配置的sessionFactory。 现在就可以像使用Hibernate一样使用jBPM。

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档