好文档 - 专业文书写作范文服务资料分享网站

深入浅出 jBPM 电子书

天下 分享 时间: 加入收藏 我要投稿 点赞

ctx.leaveNode(ctx, \ } else {

ctx.leaveNode(ctx, \ } } }

在定制的节点实现中可以创建和联合(join)令牌,关于如何做的示例,请签出Jbpm源码中fork和join节点的实现部分:-)

9.10 图执行

Jbpm的图执行模型基于的是流程定义的解释和命令链设计模式(chain of command pattern)。

解释流程定义意思是把流程定义存储到数据库中,在运行时流程执行期间流程定义信息被使用。需要注意的是:我们使用hibernate的二级缓存来避免在运行时加载流程定义信息,因为流程定义不会改变(参考流程版本部分),hibernate可以在内存中缓存流程定义。

命令链设计模式意味着图中每个节点负责传播流程执行,如果一个节点不传播执行,则它表现为一个等待状态。

这个意思是说流程实例开始执行之后一直执行,直到进入一个等待状态。

令牌代表一个执行路径,令牌拥有一个指向流程图中节点的指针,在等待状态,令牌可以被持久化到数据库。现在让我们看看计算令牌执行的算法:当一个信号发送到令牌时执行开始,然后执行通过转换和节点使用命令链设计模式被传递。下面是类图中的相关方法:

图 9.4 图执行相关方法

当令牌在节点内时,信号可以被发送到令牌,发送信号是开始执行的指示。信号必须指定令牌当前节点的离开转换,默认的是第一个离开转换。信号发送到令牌,令牌获取它的当前节点并且调用Node.leave(ExecutionContext, Transition)方法,可以把ExecutionContext看作令牌,因为ExecutionContext中的主要对象就是一个令牌。

Node.leave(ExecutionContext, Transition)方法会激活转换事件并且调用转换的目标节点的Node.enter(ExecutionContext)方法,而Node.enter(ExecutionContext)方法会激活node-enter事件并且调用Node.execute(ExecutionContext)方法。每种类型的节点在execute方法中都有它们自己实现的行为,每个节点有责任通过再调用Node.leave(ExecutionContext, Transition)传播图的执行。概括如下:

l Token.signal(Transition)

l -->Node.leave(ExecutionContext, Transition) l -->Transition.take(ExecutionContext)

l -->Node.enter(ExecutionContext) l -->Node.execute(ExecutionContext)

注意,完成下一个状态的计算,包括调用动作是在客户端线程中完成的。一个误解是所有计算必须在客户端线程完成,象任何异步调用,你也可以使用异步消息(JMS)来完成。当消息被发送到与流程实例更新的同一事务中时,所有的同步问题必须小心对待。某些工作流系统在图的所有节点之间使用异步消息,除了在高吞吐量的环境里之外,这个算法可以给业务流程性能调整提供更多的控制和灵活性。

9.11 事务划分

象“9.10图执行”TODO和“第4章 面向图的编程”TODO中解释的那样,Jbpm在客户端线程中运行流程,并且自然使用同步。这个意思是说,token.signal()或者taskInstance.end()只有当流程进入一个新的等待状态时才会返回。

这里我们描述的JPDL特性来自于“第13章 异步继续”的建模观点。

因为流程执行可以很容易同事务服务绑定在一起,所以在很多情况下这是一个非常直观的方法:在一个事务中流程从一个状态到另一个状态。

在某些情形,流程中的某个计算会花费很长时间,这个行为是不受欢迎的,Jbpm包含一个允许以一种异步方式来继续流程的异步消息系统用来应对这种情况。当然,在java企业应用环境,Jbpm可以被配置为使用JMS消息代理,用来代替自己所构造的消息系统。

在某些节点,JPDL支持属性async=“true”,异步节点不会在客户端线程被执行,而是通过异步消息系统发送一个消息,并且线程被返回给客户端(意味着是token.signal()或taskInstance.end()返回)。

注意,现在Jbpm客户端代码可以提交事务。消息的发送应该与流程的更新在同一事务中完成。因此事务的最后结果是令牌被移动到下一节点(尚未被执行),并且一个

org.jbpm.command.ExecuteNodeCommand消息在异步消息系统上被发送到Jbpm的命令执行器(Command Executor)。

Jbpm的命令执行器从队列中读取并执行命令,在

org.jbpm.command.ExecuteNodeCommand下,流程通过执行节点被继续,每个命令在一个独立的事务中被执行。

因此,为了异步流程可以继续,必须需要运行一个Jbpm命令执行器,一个简单的方法是在你的Web应用中配置CommandExecutionServlet,作为选择,你应确保命令执行器线程可以运行于任何其他方式。

作为一个流程建模者,你不应该被这些异步消息所干预,主要关注点是事务划分:默认情况下Jbpm在客户端事务中运转,进行全部计算,直到进入一个等待状态。使用async=“true”在流程中划分事务。

让我们看一个例子:

...

客户端代码与流程执行(开始和恢复)相符合,与普通的流程(同步的)一样:

...start a transaction...

JbpmContext jbpmContext = jbpmConfiguration.createContext(); try {

ProcessInstance processInstance =

jbpmContext.newProcessInstance(\ processInstance.signal();

jbpmContext.save(processInstance); } finally {

jbpmContext.close(); }

在第一个处理之后,流程实例的根令牌将指向节点one,并且一个ExecuteNodeCommand消息被发送到命令执行器。

在并发的事务中,命令执行器从队列中读取消息,并且执行一个节点,动作可以决定传播执行或进入一个等待状态。如果动作决定传播执行,则当执行到达节点two时事务会被结束,以此类推…

第10章 上下文

上下文与流程变量有关,流程变量是维护与流程实例有关信息的“键-值”对,因为上下文必须存储在数据库中,所以使用会有一些约束。

10.1 访问变量

org.jbpm.context.exe.ContextInstance是提供流程变量服务的核心接口,你可以象如下这样从一个流程实例获取ContextInstance:

ProcessInstance processInstance = ...;

ContextInstance contextInstance = (ContextInstance) processInstance.getInstance(ContextInstance.class);

最基本的操作是:

void ContextInstance.setVariable(String variableName, Object value);

void ContextInstance.setVariable(String variableName, Object value, Token token);

Object ContextInstance.getVariable(String variableName);

Object ContextInstance.getVariable(String variableName, Token token);

变量名称是java.lang.String类型,默认情况下,Jbpm支持下列值类型:

l java.lang.String l java.lang.Boolean l java.lang.Character l java.lang.Float l java.lang.Double l java.lang.Long l java.lang.Byte l java.lang.Short l java.lang.Integer l java.lang.Date l byte[]

l java.io.Serializable l 使用hibernate持久化的类

无类型的空值(null)也可以被持久化存储。

所有其他类型都可以毫无问题的被存储在流程变量里,但是当你试图保存流程实例时会导致一个异常。

要配置Jbpm存储变量中的hibernate持久化对象,请参考存储hibernate持久化对象部分。

10.2 变量生存期

变量不是必须在流程档案中声明。在运行时,你可以把任何java对象放进变量,如果这个变量不存在,它会被创建,就象使用一个普通的java.util.Map一样。

变量可以使用如下语句删除:

ContextInstance.deleteVariable(String variableName);

ContextInstance.deleteVariable(String variableName, Token token);

现在支持类型的自动转换,这意味着允许用一个不同类型的值来覆盖变量。当然,你应该尽量限制类型转换,因为这会造成比一个普通的列更新增加更多的数据库通信。

10.3 变量持久化

变量是流程实例的一部分,保存流程实例到数据库,使数据库与流程实例保持同步,作为保存(=更新)流程实例到数据库的结果,变量也将被从数据库创建、更新和删除。有关更多信息,请参考“第7章 持久化”。

10.4 变量范围

每个执行路径(参看:令牌)拥有它自己的一组流程变量,变量请求总是在令牌上发生。流程实例有一个令牌树(参看“第4章 面向图的编程”),当请求一个没有指定令牌的变量时,默认令牌是根令牌。

变量查询递归到给定令牌的父,这与编程语言中的变量范围是相似的。

当在令牌上设置一个不存在的变量时,变量在根令牌被创建,这就意味着每个变量默认都是整个流程范围的。如果想设置一个令牌局部变量,你必须明确使用如下语句创建:

ContextInstance.createVariable(String name, Object value, Token token);

10.4.1 变量重载

变量重载的意思是说,每个执行路径可以拥有它们自己的同名变量的拷贝,它们被看作是独立的,因此可以类型不同。当你通过同一转换发起多个并发的执行路径时,变量重载将会很有趣,区分这些执行路径的唯一之处就是它们各自独立的变量。

10.4.2 变量重写

变量重写的意思是说,在嵌套执行路径中的变量覆盖更高层执行路线中的变量。通常,嵌套执行路径涉及到并发:在分支和联合之间的执行路径是到达分支的执行路径的子(嵌套)。例如,如果你在流程实例范围有一个变量“contact”,你可以在嵌套的执行路径“shipping”和“billing”中重写这个变量。

10.4.3 任务实例变量范围

有关任务实例变量的更多信息,请参考“11.4 任务实例变量”。

10.5 临时变量

当流程实例被持久化到数据库时,正常的变量作为流程实例的一部分也被持久化。在某些情况下,你可能想在委托类中使用变量,但是你不想把它保存到数据库。例如,你想从Jbpm外部传递一个数据库连接到委托类,这可以使用临时变量来完成。

临时变量的生存期与流程实例(ProcessInstance)java对象一样。

由于这个自然性,临时变量与令牌无关,因此对于一个流程实例对象只有一个临时变量map。

临时变量使用上下文实例中它们自己的一组方法进行访问,并且不需要在processdefinition.xml中声明。

深入浅出 jBPM 电子书

ctx.leaveNode(ctx,\}else{ctx.leaveNode(ctx,\}}}在定制的节点实现中可以创建和联合(join)令牌,关于如何做的示例,请签出Jbpm源码中fork和join节点的实现部分:-)9.10图执行Jbpm的图执行模型基于的是流程定义
推荐度:
点击下载文档文档为doc格式
8l9bb1yjqg01k8300sny
领取福利

微信扫码领取福利

微信扫码分享