`
newqinhao
  • 浏览: 141346 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

传智播客----- 工作流得重要部分

阅读更多
今天汤阳光老师给我们继续讲jbpm,工作流的重要的部分!

* 节点
不同的节点类型代表不同的行为。

** start-state 节点
开始节点,标识流程开始边界。开始状态有且只有一个,就是说流程中不能有任何
transition指向开始节点。

创建新的流程实例后,就有一个对应的RootToken(根令牌)指向start-state,并且
处于等待状态,需要给Token发信号(signal)才能使流程继续执行。

** end-state 节点
结束节点,标识流程的结束边界。不需要transition元素。

** task-node 节点
任务节点,可以包含任意数量的Task(任务)。当执行到一个任务节点的时候,
将会根据这个task-node中的task的定义,创建相同数量的TaskInstance(为每一
个Task都创建一个任务实例,并且分配给任务定义中指定的参与者)。然后,这
个task-node一直处于等待状态。等到这些任务实例都被完成后,才会离开当前的
节点,到达下一个节点。

如果一个task-node中没有定义任务,执行时,一进入这个节点就会马上离开,即
Token不会在这个task-node上停留,因为他发现所有的任务实例都执行完了(任
务实例的数量为0)。

** task-node的属性: signal 和 create-tasks
*** signal属性:指定完成任务实例对执行流程的影响(发信号)。
(指定哪个任务实例完成后会发信号离开节点)

属性可取的值:
    last:默认值.当最后一个实例被完成时候发信号。当在这个入口没有任务被
生成时候,流程继续执行(发信号)
    first:当第一个实例被完成时候发信号。当在这个入口没有任务被生成时
候,执行继续.
    never:不管任务实例是否完成,都不发信号。
    unsynchronized:进入节点后就发信号,不管任务是否没建立或有没有完成。
就是说任务的执行和流程执行互不影响。
    last-wait:当进入节点时没有任务实例被创建时,就会一直处于等待状态,
直到任务实例被创建;创建任务实例后,就是当所有的实例都执行完成后发信号
(和last一样了)。
    first-wait: 和last-wait一样理解。


create-tasks属性:指定在进入task-node时是否创建任务实例(默认为true)

** decision 节点
决策节点,用于计算流向: 在decision中使用DecisionHandler,或使用一个表达式。
(都是返回要使用的transition的name);


** expression(表达式)
和我们在jsp中使用的el表达式相似,只是${}改为#{}。

表达式中可以直接使用已设置的流程变量,并且可以直接使用以下变量:
  taskInstance
  processInstance
  processDefinition
  token
  taskMgmtInstance
  contextInstance


** fork / join (分支节点与合并节点)
fork(分支节点)的作用是将单个执行流程分裂成多个并发的执行流程。默认的
行为是为每个分支生成一个子令牌,并建立子令牌和主流程令牌之间的父子关
系。此时,父令牌指向fork节点,子令牌指向各个分支节点。

join(合并节点)将分支收拢。当从同一个fork中出来的所有的分支都到达该节
点的时候,join节点将结束这些分支上的子token,并给他们的父Token发一个信
号离开join节点(从fork节点直接到join节点的下一个节点,不会经过join节
点)。如果只有分支中的部分token到达时,join结点将处于等待状态。

fork和join节点要成对的出现。

如果要用jbpm-console运行含有fork节点的流程,就要给fork中的所有的
transition指定名字。否则,执行到这个fork节点的时候就会抛空指针异常。

** node 节点
可定制的节点。可以在node元素中指定一个Action子元素,可以指定一个实现了
ActionHandler接口的类,用这个类可定制这个节点的行为。这时,如是果想让流
程继续执行,需要给token发一个信号。

如果node中没有动作,他的默认行为是一到达就离开了,不作停留。


** Action
动作,是一段代码,在指定的情况下被执行。

属性:
  class   :指定处理类;
  name    :action的名字;
  ref-name:所引用的action的名字;

一个action是一段java代码,用来引入附加的处理逻辑。可以放在node节点中,
也可以放在event(事件)中,用来辅助当前节点完成业务逻辑。

Action是一种在图形表示之外增加更多技术细节的机制。可以让java代码在不修
改图结构的情况下和图关联起来。


** event
事件。

每个事件有一个动作(action)清单。当jBPM引擎产生一个事件,动作(action)清单
就会被执行. 不同的节点支持的事件类型不同,是由event元素所在的节点的类型
决定的,例如transition只有一个事件。

可以在event元素用可以指定一个动作,当指定的事件发生时,这个动作被执行。

可以给同一个事件指定多个动作,当这个事件触发的时候,这些动作执行的顺序
和定义先后顺序是一致的。

不同元素支持不同的事件类型:
一般的节点都具有的事件:node-enter,node-leave;
start-state只有node-leave;
end-state只有node-enter;
transition只有一个执行转换的事件(taking a transition)
       (所以配置时不用写event元素,而直接配置Action)
task有task-create,task-assign,task-start,task-end。

关于哪些元素支持哪些事件,可以通过文档的18.4节中的xml文件的写法中获得。

如果配置的事件类型不存在,不会报错,也不会执行。

注意:在事件中定义的动作不应该(不能)影响流程的执行。即不要在事件的动
作中给token发信号,否则会抛异常。


** 动态的创建不确定数量的任务实例
实现任务分配给多个人,需要做以下工作:
1,阻止jBPM自动创建任务实例(设置task-node的create-tasks="false");
2,在流程定义中定义的相应的任务,不指定参与者;
3,在node-enter事件中定义一个动作指定用于创建TaskInstance的类。

创建任务实例要调用方法:
  TaskMgmtInstance.createTaskInstance(Task, ExecutionContext);
其中的Task 是任务的定义,可以先得到当前的节点:
  TaskNode taskNode = (TaskNode) executionContext.getNode();
然后通过任务的名字得到任务的定义:
  Task task = taskNode.getTask("审批");


* 任务分配
任务分派有两种模式,分别是推(push)模式和拉(pull)模式。

推模式(个人任务):是在任务分派的时候,直接将任务实例分派给一个指定的
用户,任务实例进入这个用户的个人任务列表中。

拉模式(组任务):是将任务实例分派给一组用户,这个任务实例会出现在(这
个组中用户的)组任务列表中。执行组任务时,需要首先将任务实例拉到自己的
个人任务列表中,然后执行此任务。当有一个组任务被某个组用户取出后,该任
务实例就会从组任务列表中移除。(任务竞争的机制)

这两种分配任务的模式都可以使用任务分派接口AssignmentHandler来实现。任务
在定义的时候指定对应的AssignmentHandler接口实现类。引擎在创建任务实例的
时候会调用接口中的assign方法。其实现应该调用参数assignable的方法对任务
进行分派。

** push (personal task list)
分配任务的方式:
  1> 在流程定义中定义任务时,用actor-id指定;
  2> 使用AssignmentHandler,方法为assignable.setActorId(String);
  3> 在程序代码中使用TaskInstance.setActorId(String)指定;

查询个人任务列表的方法为:
  TaskMgmtSession.findTaskInstances(String actorId);

** pull (group task list)
分配任务的方式:
  1> 在流程定义中定义任务时,用pooled-actors指定(多个参与者用逗号隔开);
  2> 使用AssignmentHandler,方法为assignable.setPooledActors(String[]);
  3> 在程序代码中使用TaskInstance.setPooledActors(String[])指定;

查询组任务列表的方法为:
  TaskMgmtSession.findPooledTaskInstances(String actorId);

对于一个组任务,如果他的actorId为null,组中所有的用户都可以在组任务列表
中看到这个任务。如果使用TaskInstance.setActorId(String)方法设置这个任务
由指定的acrorId来办理,这时pooledActors中的其他人就看不到这个任务了,就
是说actorId会屏蔽pooledActors; 当这个用户因某些原因不能办理任务时,可
以把这个任务再退回到组任务列表中,方法是调用TaskInstance.setActorId(null)
设置actorId为null,这时pooledActors中的所有人又都可以看到这个任务了。

**
不管使用哪种方式分配任务,参与者的计算(确定)都是由业务层负责解释的。


通过查询组任务的api查不出个人任务,反之亦然。


** swimlane
泳道,是流程角色。这是用来指明 在一个流程中 要完成多个任务的 同一个参与
者的 机制。

在流程运行时,当第一次遇到任务实例分配给一个泳道的时候,引擎会创建相应
的泳道实例(swimlaneInstance),并计算对应的用户,其后所有分配给这个泳道
的任务实例都会分配给相同的用户。


* 变量
org.jbpm.context.exe.ContextInstance是提供流程变量服务的中央接口。

变量分为两种:流程变量和临时变量。流程变量会被持久化到数据库中;临时变
量则不会(只是在放到内存中)。

** 流程变量
变量的访问和赋值是在某一个token上进行的,缺省时,是基于root Token。

变量名的类型为java.lang.String, 支持的变量值类型。
(如果变量值是PO,则PO的id应为long型)。

每个Token(执行路线)有它自己的一套流程变量。变量的作用域和所属的Token
的生命周期一致,不同的Token上的同名变量互不影响。

如果主键值是int型(或其它非long或非String型),这个po就不能做为流程变量。
我们可以先把他保存到数据库中,然后在流程中保存这个PO的类型信息和主键信
息就可以了。

作用域:每个Token(执行路线)有它自己的一套流程变量。变量的作用域和所属
的Token 的生命周期一致,不同的Token上的同名变量互不影响。



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics