下面我们通过一个简单的部门借款流程来了解现实中的业务流程概念,流程图如下:

上
图表达了一个抽象的流程定义(Process
Definition)。之所以称之为抽象,是因为它没有表示确切的执行者。当上述的借款人被具体化为“张三”,部门主管就成为张三的部门经理“李四”,
而财务则明确为“王五”的时候,这个流程定义就被具体化,成为了一个流程实例(Process
Instance)。此外,过程中的相关人员我们称之为参与者(Actor);过程中需要参与者介入的环节称之为任务(Task);每个任务在流程实例中
的具体化称之为任务实例(Task Instance);从一个任务(结点)到另一个任务(结点)的转化过程叫做流转(Transition);而在流程中,由程序预先设定的行为如发送邮件,我们称之为活动(Action)。
通过上述样例,我们了解了业务流程中一些专有名词和概念。接下来,我们要从程序设计的角度来讲述jPDL中定义的流程对象模型。
在jPDL中,对流程的建模被划分为两大部分,一是针对“流程定义”的静态模型部分;二是针对具体“流程实例”的运行时动态模型。在这一章节,我们将详细的讲述jPDL的对象及对应的数据库设计。
静态的流程定义模型
|
编号
|
PD-001
|
|
对象
|
流程定义实体(Process
Definition)
|
|
描述
|
流程定义实体是对一个流程抽象的对象化定义,如图-002。一套系统中,用户可以定义保存多个流程定义实体,如:报销流程定义、请假流程定义、人事录用流
程定义等。每个流程定义还可以有多个不同的版本,如:针对同样的报销流程可以有修订前和修订后的两个流程定义,同时存储于jPDL数库中。用户可以通过流
程名称和版本号获取相应的流程定义。在默认请况下,系统启用最新的流程定义。
|
|
Java对象
|
org.jbpm.graph.def.ProcessDefinition
|
|
数据库表
|
JBPM_PROCESSDEFINITION该表存储流程定义的通用信息,如:流程名称、版本号
|
|
表关联说明
|
JBPM_PROCESSDEFINITION表中,每条记录有自己的数据库流水号
ID_JBPM_PROCESSDEFINITION的外键(Foreign
Keys):
- startstate_
同JBPM_NODE(流程结点)表关联。此外键指向流程定义中的起始结点ID
|
|
编号
|
PD-002
|
|
对象
|
流程结点(Node)
|
|
描述
|
流程结点是对流程中的过程环节/行为的抽象对象化定义,如图-002中的每个方框即代表一个结点。结点有两个主要职责:一,实现某个指定行为,这在
jBPM中就是执行一段制定的Java代码;二,转递、维持流程的延续,直至达到最终结点。在jPDL的结点设计中,系统开放了充分的用户行为模型,程序
员可以基于这些行为接口,实现自定义的业务功能。在jPDL中,系统预定义了一系列的Node类型,同时也允许程序员开发定义自己的Node类型。
|
|
Java对象
|
org.jbpm.graph.def.Node
|
|
数据库表
|
JBPM_NODE该表存储结点的定义信息。
|
|
表关联说明
|
JBPM_NODE表中,每条记录有自己的数据库流水号
ID_JBPM_NODE的外键(Foreign
Keys):
- processdefinition_
- 此外键说明该Node从属的流程定义对象ID
- subprocessdefinition_-
此外键指定了一个由该Node发起的子流程。在主流程离开当前结点之前,该子流程必须完成执行过程。action_
- 此外键指定该结点动作类的ID
- superstate_
- 该外键是一个自关联键,指向结点的上级父结点ID。一个子流程中的多个结点从属于同一个父流程结点。
- decisiondelegation_
– 该外键指定了结点委派的判定类ID(所谓委派判定类是指根据用户的业务逻辑,判定流程的下一个流向的Java
Class)
|
Node类型祥解:
任务结点(task-node)任务结点是代表由人介入的一个或多个任务。因此当流程运行到一个任务结点时,会生成“任务实例对象(task
instances)”,并添加到参与人的任务列表中,之后结点会处于等待状态,直到参与人完成他们的任务,并**流程继续向下执行。
状态结点(state)
状
态结点是一个典型的等待状态。同任务结点不同的是,状态结点不会向任务列表添加任务实例。当业务进程需要等待外部系统的干预时,这种结点是很有用的。假设
如下情况:在进入该结点时,通过node-enter事件向外部系统发送一个消息,然后结点进入等待状态;当外部系统完成处理,并回送一个消息,这将导致
触发一个token.signal()方法的运行,该方法重新**正在等待的流程继续下行。
判定结点(decision)判
定节点的作用就同它的命名一样,用来决定业务流程的走向。有两个不同裁决模式,两者的区别在“谁”来做决定:是由流程内部的变量,还是由外部实体来提供决
定的依据。当需要对流程执行方向做判定时,就要使用“判定结点(decision)”。有两种方法来指定判定条件。最简单的是在转向
(transitions)中添加条件元素,条件可以是能返回boolean值的EL表达式或者beanshell脚本。在运行过程中,判定结点将首先轮
训有条件设定的转向(leaving
transitions),轮训的顺序是按照XML文件中指定的。当找到第一个条件返回为true的转向时,该出口将被选中。如果所有的表换中的条件判定
都是false,则选择XML文件中排在第一位的转向作为出口。还有一种途径是在判定结点上定义一个返回转向名称的表达式,通过表达式计算返回的名称,决
定选择哪个transition.另一方式是在结点上设定“处理(handle)”元素。在结点上指定一个实现了DecisionHandler接口的
Java处理类,该类通过返回选定的transition的名称来决定流程的出口方向。
当判定结点的出口是由外部程序来给出的时候,建议使用多个transition或者具有等待状态的结点。可以通过外部的触发器结束一个等待状态并提供一个transition的判定。
分支结点(fork)
分支结点的作用是将单个执行流程分裂成多个并发的执行流程。默认的行为是为每个子流程生成一个子令牌,并建立子令牌和主流程根令牌之间的父子关系。
合并结点(join)
相
对于fork结点的分支,join结点将分支收拢。默认的行为模式是当所有的分支(由同一个fork衍生出来的分支)都到达该结点的时候,join结点将
结束这些分支上的子token,并通过token上的父子关系找到上一级流程的token,将此token通过唯一的transition传播下去。如果
只有分支中的部分token到达时,join结点将处于等待状态。
普通结点(node)普通类结点主要用于提供用户定制自己的程序代码。普通结点拥有一个action子元素,当流程到达该结点时,这个action就会被执行。可以通过实现ActionHandler接口来执行你想要的任何代码。此外普通结点也一样要负责流程的延续。
在流程图上,普通结点用来表达一个用户关心的、与业务相关的处理逻辑;相比而言Action(下文中将会提到)则允许添加业务逻辑以外的程序处理,这些程序处理在流程图上是不可见的,也是业务流程分析所不用关心的。
|
编号
|
PD-003
|
|
对象
|
流程转向(Transitions)
|
|
描述
|
流程转向是描述流程中从一个结点到另一个结点的状态转换过程,因此一个转向一定有一个源结点和一个目标结点。
在jPDL中transition的命名是通产是唯一的,结点依靠transition的命名来区别到下一结点的路径,当一个Node中存在有多个同名的
transition的时候,第一个transition将会被选中。结点转向的过程中,排在transition列表第一位置的即是默认的
transition。
|
|
Java对象
|
org.jbpm.graph.def.Transition
|
|
数据库表
|
JBPM_TRANSITION该表存储流程定义中的转向对象。
|
|
表关联说明
|
JBPM_TRANSITION表中,每条记录有自己的数据库流水号
ID_JBPM_TRANSITION的外键(Foreign
Keys):
- processdefinition_
- 该外键指向transition所属的流程定义对象ID
- from_
- 该外键指向transition的源结点ID
- to_
-该外键指向transition的目标结点ID
|
|
编号
|
PD-004
|
|
对象
|
动作(Actions)
|
|
描述
|
Actions
是指一系列的在流程事件中运行的Java代码。流程图是软件需求的传达的重要手段,但它只是软件需求的一个投影,隐藏了很多技术实现的细节。
Actions则是向流程图添加技术实现细节的一种机制,它可以很好的补充和修饰流程图。这意味着在不改变流程图结构的情况下,可以将Java的代码与之
关联。Actions通过事件(Events)同流程绑定,常用的主要事件包括:进入结点、离开结点、进行转向。请注意,同Events关联的
Actions和处于Node中的Actions是有不同的。处于Events中的Actions是通过事件触发执行的,它是典型的观察者模式,是无法影
响流程控制的流向。而处于Node中的Action则要承担起流程传递的责任。此外,Actions是可以命名的。可以通过Actions的命名在任何地
方引用该Actions。命名的Actions可以作为主流程定义的公用子元素。这个功能可以提高对Actions定义的复用。
|
|
Java对象
|
org.jbpm.graph.def.Action
|
|
数据库表
|
JBPM_ACTION该表存储流程定义中的动作对象。
|
|
表关联说明
|
JBPM_ACTION表中,每条记录有自己的数据库流水号ID_
JBPM_ACTION的外键(Foreign
Keys):
- processdefinition_
- 指明action所属的流程定义ID
- event_
- 指明action绑定的event ID
- actiondelegation_
- 指明action的委派对象ID
- exceptionhandler_
- 指定action的异常处理ID
- referencedaction_
- 指向当前action引用的action的ID
- timeraction_
- 指向当前action引用的计时器action
|
|
编号
|
PD-005
|
|
对象
|
事件(Events)
|
|
描述
|
事件表示流程执行中的某个特定的时刻。在流程执行的过程中,通过jBPM的引擎触发事件,这通常发生在jbpm计算后续状态的时候。事件总是和流程中的元
素绑定,这些元素包括:流程定义(process
definition)、流程结点(node)、流程转向(transition)和任务(task)。不同的元素会触发不同的事件,拿node元素来
说,有
node-enter事件和node-leave事件。事件是action的钩子,一个事件可以回调一系列的action。当jBPM引擎触发事件的时
候,事件中绑定的action就会被执行。在jBPM中,事件模型是可传播的。一个子元素触发的事件,将逐层向上传播到顶层的流程定义元素。这样的设计使
得事件可以被集中化处理。
|
|
Java对象
|
org.jbpm.graph.def.
Event
|
|
数据库表
|
JBPM_EVENT该表存储流程定义中的事件对象,这些事件与相关的action绑定。
|
|
表关联说明
|
JBPM_EVENT表中,每条记录有自己的数据库流水号ID_
- JBPM_EVENT的外键(Foreign
Keys):
- processdefinition_
- 指向event所属的流程定义ID
- node_
- 指向event所属的node ID
- transition_
- 指向event所属的transition ID
- task_
- 指向event所属的任务ID
|
|
编号
|
PD-006
|
|
对象
|
任务(Task)
|
|
描述
|
任务作为流程定义中的一部分,定义了如何创建任务实例(Task
instances)以及任务分配。任务可以在任务结点(Task-Node)和流程定义(process-definition)
两个地方定义。通常会在一个任务结点中定义一个或多个的任务。在这种情况下,任务结点表示在流程中等待用户处理的交互操作。业务流程会停留在任务处,等待
用户完成相应的操作之后继续。任务也可在流程定义中声明。通过任务名,可以找到相应的任务定义,并引用他们。实际上任何有命名的任务都可以通过名字被引
用。在整个的流程定义中,任务名必须是唯一的。此外,还可以给任务设定优先级,这些优先级属性将成为任务实例化时的默认设置。任务实例可以在之后的运行中
改变优先级。.
|
|
Java对象
|
org.jbpm.taskmgmt.def.Task
|
|
数据库表
|
JBPM_TASK该表存储流程定义中声明的任务对象。
|
|
表关联说明
|
JBPM_TASK表中,每条记录有自己的数据库流水号ID_
JBPM_TASK的外键(Foreign
Keys):
-
processdefinition_
-指向task所属的流程定义ID
-
taskmgmtdefinition_
- 指向task引用的TaskMgmtDefintion对象ID
-
tasknode_ -
指向task所属的任务结点ID
-
startstate_ -指向task所属流程的起始结点ID
-
assignmentdelegation_
- 指定task委派处理的class对象的ID
-
swimlane_ -
指定task要授权的swimlane(角色)ID
-
taskcontroller_
- 指定一个task赋值的委托类
|
上述我们剖析了jPDL业务流程定义中最重要的几个静态对象,说明了它们的概念、作用、行为特征及关联关系。在正式的运行环境中,这些对象定义被jPDL持久化于数据库中,当用户发起一个业务流程时,被系统实例化。在下面的小节中,我们要讲述流程被实例化后的数据模型。
具体化的流程实例模型
本章节介绍流程实例中最重要的三个对象:流程实例(Process
Instance)、令牌(Token)、任务实例(Task
Instance).
|
编号
|
PI-001
|
|
对象
|
流程实例(Process
Instance)
|
|
描述
|
流程实例是流程定义的运行时状态,它记录了一个流程运行的起始时间、结束时间等状态信息
|
|
Java对象
|
org.jbpm.graph.exe.ProcessInstance
|
|
数据库表
|
JBPM_PROCESSINSTANCE该表存储运行时的流程对象信息。
|
|
表关联说明
|
JBPM_PROCESSINSTANCE表中,每条记录有自己的数据库流水号
ID_JBPM_PROCESSINSTANCE的外键(Foreign
Keys):
-
processdefinition_
- 该流程实例对应的流程定义的ID
-
roottoken_ -
该流程实例引用的跟令牌
-
superprocesstoken_
- 如果当前流程是某个流程实例的子流程,则指向该父流程的ID
|
|
编号
|
PI-002
|
|
对象
|
令牌(Token)
|
|
描述
|
令牌代表一个流程执行的路径,它维护着流程定义中各个结点的指针,同时记录了流程当前执行的位置。
|
|
Java对象
|
org.jbpm.graph.exe.Token
|
|
数据库表
|
JBPM_TOKEN该表存储运行时令牌对象信息,它表示当前流程执行到的位置。
|
|
表关联说明
|
JBPM_TOKEN表中,每条记录有自己的数据库流水号ID_
JBPM_TOKEN的外键(Foreign
Keys):
-
processinstance_
- 指向该令牌所属的流程实例的ID。
-
subprocessinstance_
- 指向该令牌所属的子流程实例ID。
-
node_ -
令牌所在(所指向的)的当前节点ID.
-
parent_ -
如果当前令牌是一个分支流程或子流程的令牌,则该值指向其父令牌ID。
|
|
编号
|
PI-003
|
|
对象
|
任务实例(Task
Instance)
|
|
描述
|
一个任务实例对象可以分配给指定的操作者处理,当任务完成后,将触发流程继续下行。任务实例的生命周期很简单,生成实例-->开始处理-->任
务结束。从弹性设计考虑出发,任务的分配不属于实例生命周期的一部分,任务是否被分配是不会影响其生命周期过程的。当流程进入一个任务结点的时候,结点上
任务被实例化;用户通过访问系统的界面组件,获取自己的任务列表,可以进行任务委派、处理或直接结束任务。任务实例记录着任务创建的时间、结束时间,这些
信息可以通过TaskInstance对象中的getter方法获取。一个任务实例的结束时间标识它的完成,在后绪的任务查询中,该实例不会被取出,但实例的记录仍保留于数据库中。
|
|
Java对象
|
org.jbpm.taskmgmt.exe.TaskInstance
|
|
数据库表
|
JBPM_ TASKINSTANCE该表存储运行时任务实例信息。
|
|
表关联说明
|
JBPM_ TASKINSTANCE表中,每条记录有自己的数据库流水号ID_
JBPM_ TASKINSTANCE的外键(Foreign
Keys):
-
task_ -
指向定义该实例的任务ID
-
token_ -
指向任务实例对应的令牌ID
-
swimlaneinstatnce_
- swimlane
实例,表示处理该任务的角色
-
taskmgmtinstance_
- 管理该任务的模块实例ID
|
jPDL语言主要XML元素大纲
本章节将介绍jPDL语言中,主要几个XML元素的属性及相关描述。
<process-definition>(流程定义)
|
名称
|
类型
|
多样性
|
描述
|
|
name
|
属性
|
可选
|
流程的名称
|
|
swimlane
|
元素
|
[0..*]
|
在流程中使用的swimlanes
。
swimlanes是过程中的用户角色,可以用于任务的委派分配
|
|
start-state
|
元素
|
[0..1]
|
流程的起始状态结点
|
|
{end-state|state|node|
task-node|process-state| super-state|fork|join|decision}
|
元素
|
[0..*]
|
流程定义中出现的各类结点
|
|
event
|
元素
|
[0..*]
|
流程中的事件,可看成是action的容器
|
|
{action|script|create-timer
|cancel-timer}
|
元素
|
[0..*]
|
全局定义的action,可以在
events和transitions中通过命名引用
|
|
task
|
元素
|
[0..*]
|
全局定义的task,可以在action中使用命名来引用.
|
|
exception-handler
|
元素
|
[0..*]
|
异常处理类,用来处理委派类抛出的异常.
|
<node>(节点)
|
名称
|
类型
|
多样性
|
描述
|
|
{action|script|create-timer |cancel-timer}
|
元素
|
1
|
定制的结点动作
|
|
common node elements
|
|
|
参考common
node elements
|
<common node elements>(通用结点元素)
|
名称
|
类型
|
多样性
|
描述
|
|
name
|
属性
|
必须
|
结点名称
|
|
async
|
属性
|
{ true |
false }, false is the default
|
设置成true,则结点以异步方式运行
|
|
transition
|
元素
|
[0..*]
|
离开结点的转向.每个转向必须有一个可区别的名字。最多只允许一个转向是没有命名。第一个转向指定为默认的转向,当没有给结点指定转向时,将使用默认转向。
|
|
event
|
元素
|
[0..*]
|
支持的事件类型(node-enter
| node-leave)
|
|
exception-handler
|
元素
|
[0..*]
|
针对委派类抛出异常的处理
|
|
timer
|
元素
|
[0..*]
|
指定一个计数器监视结点上的执行过程
|
|
|
|
|
|
<start-state>(起始状态结点)
|
名称
|
类型
|
多样性
|
描述
|
|
name
|
属性
|
可选
|
起始结点名称
|
|
task
|
元素
|
[0..1]
|
此任务会创建一个流程实例或者捕获流程的初始化者
|
|
event
|
元素
|
[0..*]
|
支持结点的事件:{node-leave}
|
|
transition
|
元素
|
[0..*]
|
流程转向,必须有唯一命名
|
|
exception-handler
|
元素
|
[0..*]
|
对委派类异常的处理者
|
<end-state>(终止状态结点)
|
名称
|
类型
|
多样性
|
描述
|
|
name
|
属性
|
必须
|
终止结点名称
|
|
event
|
元素
|
[0..*]
|
支持的结点事件:{node-enter}
|
|
exception-handler
|
元素
|
[0..*]
|
对委派类异常的处理者
|
<task-node>(任务结点)
|
名称
|
类型
|
多样性
|
描述
|
|
signal
|
属性
|
可选
|
值类型有:{unsynchronized|never|first|first-wait|last|last-wait},
默认为last.
该属性定义了任务完成对流程延续的效果。
|
|
create-tasks
|
属性
|
可选
|
值类型有:{yes|no|true|false},默认值为true,也可以设置为false。用户可以在结点的node-enter事件中定义自己action,由action来生成任务,并且将此属性设置为false。
|
|
end-tasks
|
属性
|
可选
|
值类型有:{yes|no|true|false},默认值为false.
当设置为true的时候,所有未结束任务在node-leave
事件中会被关闭。
|
|
task
|
属性
|
[0..*]
|
当流程执行到当前结点时,将生成任务列表中的任务。
|
|
common node elements
|
|
|
参考common
node elements
|
<fork>(分叉)
|
名称
|
类型
|
多样性
|
描述
|
|
common node elements
|
|
|
参考
common node elements
|
<join>(合并)
|
名称
|
类型
|
多样性
|
描述
|
|
common node elements
|
|
|
参考
common node elements
|