JBPM4.3使用说明

JBPM4.3使用说明

 

安装及整合

目录结构

下载JBPM4.3 下载地址:http://sourceforge.net/projects/jbpm/files/a)%20jBPM%204/

JBPM4.3的包结构目录为:

其中doc目录为jbpm的帮助文档,包含一份user guide和一份devguide以及javadocs,schemadocs, 我们主要关注的是user guide。 如果想深入的了解JBPM,需要学习devguide

 

Example目录是Jbpm自带的例子。

Install目录是我们的安装目录,这个目录就是方便我们安装及整合Jbpm 的目录,非常的人性化。JBPM的自动化部署是基于ant,需要我们在系统中安装ant(过会将使用这个目录进行安装描述)


lib
目录是jbpm所有依赖包的目录,如果你直接把这个目录的lib copy到你项目的lib中会出现jar冲突的问题。整合这些jar是个麻烦的事情。

 

MigrationJBPM3JBPM4升级的一个目录,我们用不着。

 

SrcJBPM4.3的源码包

 

Jbpm.jarJbpm4.3jar

 

安装JBPM

 

打开cmd,切换到{jbpm.home}/install目录。使用ant –p命令(需安装ant,并配置好环境变量这个命令描述了你可以自动化的所有工作。如图:

 

 

如:你想连接数据库把JBPM的表都建好,首先得告诉他你想连哪个数据库以及用户名密码,修改{jbpm.home}/install目录下的build.xml中的第9句,里面有多种数据库可以选择,我们写上oracle。 然后再找到{jbpm.install}/install/jdbc目录下的oracle.properties。将里面的内容改成你的数据库连接内容。然后再在命令行下执行ant create.jbpm.schema

 

如果你嫌这样很麻烦,那你就自己连上数据库,找到{jbpm-home}/install/src/db/create/目录下相应数据库的create.sql 然后复制进去就OK。删除的话就使用drop目录下的drop.sql

 

还有很多其它有用的命令,如ant get.eclipse 这样直接下载了一个包含了流程设计器的eclipse jee ant get.tomcat 直接下载一个配置好了环境的tomcat。这个tomcat已经放入了那些jbpm依赖的jar。执行完ant get.tomcat后就可以使用ant demo.setup.tomcat就可以把它的例子放到tomcat下运行  等等

 

整合spring

JBPM4.3整合spring非常的简单,它已经内置了对spring的支持。

我们找到{jbpm.home}/install/src/cfg/spring 目录。打开applicationContext.xml

<bean id="springHelper" class="org.jbpm.pvm.internal.processengine.SpringHelper" />

 <bean id="processEngine" factory-bean="springHelper" factory-method="createProcessEngine" />

这两行复制到你工程中的spring配置文件中。在sessionFacotry中加入:

<property name="configLocation" value="classpath:jbpm.hibernate.cfg.xml" />

再把{jbpm.home}/install/src/cfg/jbpm下的spring.jbpm.cfg.xml复制到你的classpath中,改名为jbpm.cfg.xml

这样就配置成功了。

然后如果你在流程定义的时候需要引用bean比如event on=”start” expr=”#{xxxBeanListener}”  使用它的表达式获取bean

 

参看dev guideChapter17 Spring整合一章

 

安装流程设计器:

使用eclipse3.5  Help-Install New Software-Archive –定位到${jbpm.home}/install/src/gpd/jbpm-gpd-site.zip  确定重启 eclipse OK

安装整合过程中的问题  参看:http://www.iteye.com/topic/577078 

JBPM4概览

PVM

PVM简介:PVM (Process Virtual Machine), 主要是想作为一个开发平台,在这个平台上,可以很方便的开发工作流,服务编制(orchestration),BPM等等.就比如 说jPDL这套语法的内部实现就是基于PVM.将来基于PVM可以开发一个符合WS-BPEL 2.0的模块. PVM可以简单的看成是一个状态机

架构图:

 

具体参考:http://people.apache.org/~jeffyu/articles/zh_CN/jbpm/(这篇文章很不错)

Jbpm 服务简介        

我们开发中主要会使用到PVM提供的几类服务:

查看org.jbpm.api.ProcessEngine.java,这个工厂类提供了所有对外发布的服务。包含:

1)      RepositoryService getRepositoryService();//获取与流程部署有关的方法:如部署一个流程定义的xml文件:processEngine.getRepositoryService().createDeployment().addResourceFromClasspath(“com/xx/jpdl/xx.jpdl.xml”);还可以部署zip压缩文件,其中zip压缩文件中要包含流程定义的xml文件以及自动生成图片。

删除流程定processEngine.getRepositoryService().deleteDeployment(java.lang.String deploymentId) 

创建一个流程部署的查询 processEngine.getRepositoryService().createDeploymentQuery()

2ExecutionService getExecutionService();  获取一个管理流程执行的服务对象

包含方法:startProcessInstanceByIdString processDefinationId) 根据流程定义ID启动一个流程实例,返回流程实例ID 。我们在启动流程的时候会调用这个方法

ProcessInstance startProcessInstanceById(String processDefinitionId, Map<String, Object> variables);//启动流程实例并传入流程变量

ProcessInstance signalExecutionById(String executionId);//传入执行ID触发流程执行

其中可以根据流程实例ID 获取Execution对象 如:Execution exec = this.processEngine.getExecutionService().createProcessInstanceQuery().processInstanceId(processId).uniqueResult().findActiveExecutionIn("xiaojia");

ProcessInstanceQuery createProcessInstanceQuery();//创建一个流程实例的查询对象

void endProcessInstance(String processInstanceId, String state);//结束一个流程实例,任何时候你都可以结束一个流程

还有其它方法,可以查看org.jbpm.api.ExecutionService源代码以及它的默认实现org.jbpm.pvm.internal.svc. ExecutionServiceImpl 

HistoryService getHistoryService();//获得历史流程实例记录和历史任务处理记录等信息

当一个task完成后,它就会被删除并在HistoryTask表中重新创建。所以,查询历史处理的任务记录必须通过HistoryService处理。

这里面只有查询方法,如使用 processEngine.getHistroyService().createHistoryTaskService().executionId(processId).list();查询指定流程实例的任务历史处理记录

还有其它方法可以查看api

TaskService getTaskService();//任务处理Service

这个服务提供了创建新任务newTask(),任务授权assignTask(..),完成任务completeTask(..),添加任务批注addTaskComment(..),查询指定用户的当前任务列表findPersonalTasks(..) ,删除任务deleteTask(..)等。

ManagementService getManagementService();//主要是JBPM提供的JOB服务

IdentityService getIdentityService();//使用这个类可能需要重新实现IdentitySession接口,并配置到jbpm.cfg.xml文件中。具体没有详细了解

JPDL简介

1.      Start state

开始节点  流程开始,每个流程定义文件只能有一个开始节点。

2.      Task node

任务节点  人工参与,调用processEngine.getTaskService().complete()完成任务

3.      State node

状态节点

需要使用execution.signalExcution()触发流程流转

4.      Descision Node

流程流向判断节点

指定condition 条件或者DesisionHandler

5.      Fork node

分支节点,任务并行处理

6.      Join node

任务聚合节点

7.      End State

任务结束节点  可以有多个结束节点

8.      Transition

控制任务流向

9.      Event

事件触发 可以在任何节点加事件触发处理

 

具体参看${JPBM.HOME}/doc/userguide文档 关于JPDL的描述

 

请假流程定义示例

<?xml version="1.0" encoding="UTF-8"?>

 

<process key="leave" name="leave" xmlns="http://jbpm.org/4.0/jpdl">

   <start g="493,45,48,48" name="开始">

      <transition g="-79,-22" name="to exclusive1" to="判断 "/>

   </start>

   <decision g="493,141,48,48" name="判断">

      <transition g="-73,-22" name="to manager" to="部门经理审批">

           <condition expr="#{days&lt;=2}"/><!—使用表达式定义流转条件:小于2天部门经理审批,大于2天分管经理审批 –->

      </transition>

      <transition g="-75,-22" name="to fenguan2" to="分管经理审批"/>

   </decision>

   <task g="364,243,92,52" name="部门经理审批" form="leave!managerAuditForward.action">

<!—注:这里的指定Taskform ,即任务处理的url,这样用户在查看代办任务列表中,点击处理任务(url即这儿的form)即可到达任务处理页面  -- >

        <assignment-handler expr="#{leaveManagerAssign}">

        </assignment-handler>

      <transition g="-68,-22" name="to guidang" to="归档"/>

      <transition name="to end" to="end1" g="279,268:-50,-22"/>

   </task>

   <task g="625,232,92,52" name="分管经理审批">

       <assignment-handler expr="#{leaveFenguan2Assign}">

        </assignment-handler>

      <transition g="-42,-22" name="to ceo" to="归档"/>

   </task>

 

   <state g="520,451,92,52" name="归档">

        <on event="start">

                  <event-listener expr="#{guidangListener}">                

             </event-listener>

         </on>

      <transition g="-58,-22" name="to xiaojia" to="销假"/>

   </state>

   <state g="526,547,92,52" name="销假">

        <on event="start">

                <event-listener expr="#{xiaojiaListener}">               

             </event-listener>

         </on>

      <transition g="-50,-22" name="to end1" to="结束"/>

   </state>

<end g="273,539,48,48" name="结束"/>

</process>

 

注:授权处理器代码:

public class LeaveFenguanAssignment implements AssignmentHandler{

       public void assign(Assignable assignable, OpenExecution execution)

                     throws Exception {

              assignable.setAssignee("2");

              //简单授权给用户2处理此任务

       }

}

监听器处理代码:

public class ArchiveListener implements EventListener{

       public void notify(EventListenerExecution execution) throws Exception {

              //SendEmail,Logger,SendMessage etc

       }

}

 

                                                                                                 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.JPDL的流程定义元素 1)第一层:GraphElement 这个容易理解,因为在画流程定义时,每个拖拉的对象都是一个graph的元素。GraphElement有四个属性: (1)processDefine 表示当前元素属于哪个流程定义 (2)events 表示可以接收哪些event (3)name 名字 (4)exceptionHandlers 异常处理类集合(List) 2)第二层:node、processDefinition、Transition、Task 它们都继承自GraphElement (1)processDefinition表示流程定义(implements NodeCollection),它有下面的属性:name、version、nodes、startState。nodes表示流程中所有的node,startState用于启动流程时找到首节点。 (2)Transition表示转移,它有三个属性:from(Node),to(Node),supportedEventTypes表示支持的event类型 (3)node表示节点,它有四个属性:leaving transitions、arriving transitions、action、superState。 (4)Task 定义任务 3)第三层:各种不同的node 它们都继承自node。 Decision、EndState、Fork、Join、Merge、Milestone、 InterleaveEnd、InterleaveStart、ProcessState、State。 2.jBPM的token jbpm中最重要的概念,应该是令牌(Token)和信令(Signal)。在整个流程实例运行过程中,我们可以迅速的利用token得到其当前的current state。在解决“并行”等(比如Fork)问题时,jBpm让Token对象维护了父子关系,这种关系在涉及到Fork的时候会产生。 jBpm让Token这个对象身兼了多种使命: (1)快速定位current state (2)用于fork,join算法 (3)用于告知任务执行者的任务索引。 如下代码: //pd是process definition,pi是process instance ProcessInstance pi = new ProcessInstance( pd ); //得到根令牌 Token token = pi.getRootToken(); //发信令 token.signal(); Token的signal方法也可以传入transition参数,这个方法把信令发送给Token,这样,令牌将被激活,并沿指定的transition离开当前的状态(如果没有指定transition,将沿缺省的transition 离开当前状态)。 jbpm是怎么实现的呢?其实很简单: 1)Token记录了当前的状态(current state),只有当前的状态(或称节点)拥有该令牌 2)向TOKEN发signal后,当前状态收到该signal 3)当前状态把令牌传给signal中指定的transition 4)transition收到令牌后,不强占,马上把令牌传给下个状态. 5)根据令牌的位置,流程的状态已经发生改变. 3.process definition 一个process definition代表了一个正式的业务流程,它以一个流程图为基础。这个流程图由许多node和transition组成。每个node在这个流程图里都有着各自特殊的类型,这些不同的类型决定了node在运行时的不同行为。一个process definition只有一个start state 。 4.token 一个token代表了一条执行路径,它包含了这条执行路径的当前的执行状态(current state)。 5.process instance 一个process instance(流程实例)即一个process definition(流程定义)的流程执行实例。一个process definition可以对应多个process instance。当一个process instance被创建的时候,一个主执行路径token同时被创建,这个token叫做root token,它指向流程定义的start state(processDefinition.getStartState()==token.getNode())。 6.signal 一个signal 发送给token通知token 继续流程的执行。如果signal 没有指定transition,token将沿缺省的transition离开当前状态,如果signal 指定transition,token将沿指定的transition离开当前的状态。看源代码可以看到发给process instance的signal 其实都是发送给了root token。 7.Actions jbpm提供了灵活的action ,当流程执行,token 进入node和transition时,会触发相应的一些event(事件)。在这些event上附上我们自己写的action,就会带动action 的执行。action里是我们自己的相关java操作代码,非常方便。注意的是event(事件)是内置的,无法扩展。另外,action也可以直接挂在node上,而不依赖于event(事件)的触发,这个很重要。 8.node 一个流程图由许多node和transition组成。每个node都有一种类型,这个类型决定了当流程执行到这个node时的不同行为。jbpm有一组node type可以供你选择,当然你可以定制自己node 。 node的作用 node有两个主要的作用: 1)执行java代码,比如说创建task instance(任务实例)、发出通知、更新数据库等等。很典型的就是在node 上挂上我们的action 2) 控制流程的执行: A、等待状态:流程进入到这个node时将处于等待状态,直到一个signal 的发出 B、流程将沿着一个leaving transition越过这个node,这种情况特殊一点,需要有个action挂在这个node上(注意这个action不是event触发的!),action中将会调用到API里 executionContext.leaveNode(String transitionName),transitionName即这里的leaving transition名字。 C、创建新的执行路径: 很典型的就是fork node。流程在这里会分叉,产生新的执行路径。这样就创建了新的token,每个新的token代表一个新的执行路径。注意的是,这些新的token和产生前的token是父子关系! D、结束执行路径:一个node可以结束一条执行路径,这同样意味着相应的token的结束和流程的结束。 9.流程图中的node type 1)task-node 一个task-node可以包含一个或多个task,这些task分配给特定的user。当流程执行到task-node时,task instance将会被创建,一个task对应一个task instance。task instances 创建后,task-node就处于等待状态。当所有的task instances被特定的user执行完毕后,将会发出一个新的signal 到token,即流程继续执行。 2)state state是一个纯粹的wait state(等待状态)。它和task-node的区别就是它不会创建task instances。很典型的用法是,当进入这个节点时(通过绑定一个action到node-enter event),发送一条消息到外部的系统,然后流程就处于等待状态。外部系统完成一些操作后返回一条消息,这个消息触发一个signal 到token,然后流程继续执行。(不常用) 3)decision 当需要在流程中根据不同条件来判断执行不同路径时,就可以用decision节点。两种方法:最简单的是在transitions里增加condition elements(条件),condition是beanshell script写的,它返回一个boolean。当运行的时候,decision节点将会在它的 leaving transitions里循环,同时比较 leaving transitions里的condition,最先返回'true'的condition,那个leaving transitions将会被执行;作为选择,你可以实现DecisionHandler接口,它有一个decide()方法,该方法返回一个String(leaving transition的名字)。 4)fork fork节点把一条执行路径分离成多条同时进行(并发)的执行路径,每条离开fork节点的路径产生一个子token。 5)join 默认情况下,join节点会认为所有到达该节点的token都有着相同的父token。join 节点会结束每一个到达该节点的token,当所有的子token都到达该节点后,父token会激活。当仍然有子token处于活动状态时,join 节点是wait state(等待状态)。 6)node node节点就是让你挂自己的action用的(注意:不是event触发!),当流程到达该节点时,action会被执行。你的action要实现ActionHandler接口。同样,在你的action里要控制流程。 10. Actions的说明 存在两种action,一种是 event触发的action,一种是挂在node 节点的action。要注意它们的区别,event触发的action无法控制流程,也就是说它无法决定流程经过这个节点后下一步将到哪一个leaving transition;而挂在node 节点的action就不同,它可以控制流程。不管是哪一种action都要实现ActionHandler接口。 11. Task(任务) jbpm一个相当重要的功能就是对任务进行管理。Task(任务)是流程定义里的一部分,它决定了task instance的创建和分配。Task(任务)可以在task-node节点下定义,也可以挂在process-definition节点下。最普遍的方式是在task-node节点下定义一个或多个任务。默认情况下,流程在task-node节点会处于等待状态,直到所有的任务被执行完毕。任务的名称在整个流程中必须是唯一的。一个TaskNode对应多个Task。 对于这样的流程定义: xml 代码 1. <task-node name='a'> 2. <task name='laundry' /> 3. <task name='dishes' /> 4. <task name='change nappy' /> 5. <transition to='b' /> 6. </task-node> 只有当节点中的三个任务都完成后,流程才进入后面的节点 对于这样的流程定义: xml 代码 1. <task-node name='a' signal='first'>> 2. <task name='laundry' /> 3. <task name='dishes' /> 4. <task name='change nappy' /> 5. <transition to='b' /> 6. </task-node> 当第一个任务完成后,token就指向后面的节点 对于这样的流程定义: xml 代码 1. <task-node name='a' signal='never'>> 2. <task name='laundry' /> 3. <task name='dishes' /> 4. <task name='change nappy' /> 5. <transition to='b' /> 6. </task-node> 三个任务都完成后,token仍然不会指向后面的节点;需要自己手动调用processInstance.signal()才会驱动流程到下面的节点。 对于这样的流程定义: xml 代码 1. <task-node name='a' signal='unsynchronized'>> 2. <task name='laundry' /> 3. <task name='dishes' /> 4. <task name='change nappy' /> 5. <transition to='b' /> 6. </task-node> token不会在本节点停留,而是直接到后面的节点 12. jbpm的任务管理实现 一个Task instance(任务实例)可以被分配给一个actorId (java.lang.String)。所有的Task instance都被保存在数据库中的表jbpm_taskinstance里。当你想得到特定用户的任务清单时,你就可以通过一个与用户关联的actorId来查询这张表。 一个流程定义有一个TaskMgmtDefinition;一个TaskMgmtDefinition对应多个swimlane,同时对应多个task;一个swimlane有多个task,可以从TaskMgmtDefinition中通过task的名称直接获取相应的task; swimlane对象有四个属性,分别是name(名字)、assignmentDelegation(分配代理类)、taskMgmtDefinition、tasks(Set 对应多个task),可以增加task task对象主要的属性:taskMgmtDefinition、swimlane、assignmentDelegation、taskNode,需要注意的是swimlane和assignmentDelegation中间只是可以一个属性有值,因为它们都和任务的分配有关系。 一个流程实例有一个TaskMgmtInstance;一个TaskMgmtInstance对应多个swimlaneInstance,同时对应多个taskInstance;一个swimlaneInstance有多个taskInstance,可以从TaskMgmtInstance中直接获取相应的taskInstance; swimlaneInstance对象主要有五个属性,分别是name、actorId、pooledActors(Set)、swimlane、taskMgmtInstance。 taskInstance对象的主要属性:name、actorId、task、swimlaneInstance、taskMgmtInstance、pooledActors。 当对任务进行分配时,一般需要实现AssignmentHandler这个接口,这个接口的方法只有一个: void assign( Assignable assignable, ExecutionContext executionContext) throws Exception; 一个典型的实现(把名字是'change nappy'的任务交给NappyAssignmentHandler这个类来分配) xml 代码 1. <task name='change nappy'> 2. <assignment class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' /> 3. task> NappyAssignmentHandler类: java 代码 1. public void assign(Assignable assignable, ExecutionContext executionContext) { 2. assignable.setActorId("papa"); 3. } 同样,Assignable只是一个接口,它有两个方法:setActorId()和setPooledActors(),Assignable的具体实现类也是两个:swimlaneInstancehe和taskInstance。这样就不不难理解整个任务分配流程了: 1、流程进入TaskNode节点,执行TaskNode类的execute()方法,该方法首先获得TaskMgmtInstance实例,然后通过它来创建TaskInstance。taskMgmtInstance.createTaskInstance(task, executionContext); 2、在上面的createTaskInstance(task, executionContext)里,该方法调用了taskInstance.assign(executionContext)对taskInstance进行分配。 3、在assign(executionContext)方法里,首先会判断task属性里是否存在swimlane,如果有的话,这个taskInstance就会分配给swimlane指定的ActorId或 PooledActors;如果不存在,再去找task属性里 assignmentDelegation(分配代理类)通过代理类(即我们自己写的实现AssignmentHandler这个接口的类)指定ActorId或 PooledActors。 13. jbpm的用户角色管理 jbpm在用户角色管理上共设计了四个类:Entity、Membership、Group、User。 Entity类是其他三个类的父类,它包含了两个属性:name(String)、permissions(Set); User类继承Entity类,包含三个属性:password(String)、email(String)、memberships(Set); Group类继承Entity类,包含四个属性: type(String)、parent(Group)、children(Set)、memberships(Set); Membership类继承Entity类,包含三个属性:role(String)、user(User)、group(Group) 很明显,一个user对应一个用户,一个group对应一个用户组,它们之间通过membership关联,并且一个user可以属于多个不同类型(type)的group,user和 group之间是多对多的关系。Membership类的role属性个人感觉用途不大,反倒是name属性代表了user在group里的role(角色)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值