jBPM jPDL 用户开发手册 3.2.3 - 第10章

10章流程建模

10.1. 概述

流程定义代表业务流程的正式规范并且基于有向图。图由节点和转换组成。图中的每个节点指定类型。节点类型定义运行时行为。一个流程定义绝对有一个开始状态。
令牌(token)是一个执行路径。一个令牌是维护图中一个节点指针的运行时概念。
流程实例是一个流程定义的执行。当一个流程实例被创建时,令牌为主执行路径创建。这个令牌叫做流程实例的根令牌并且它被放在流程定义的开始状态上。
Signal指示一个令牌继续图执行。当收到一个未命名的signal时,领先将离开它的当前节点通过缺省的离开转换。当在signal中指定一个被命名的转换时,节点将通过指定的转换离开当前节点。Signal让流程实例分派到根令牌。

在令牌进入节点后,这个节点被执行。节点自己负责图执行连续(continuation of the graph execution)。图执行连续完成后使令牌离开这个节点。每个节点类型为图执行连续实现一个不同的行为。不传播执行的节点将成为状态节点。

动作(Actions)是在流程执行里的事件上被执行的java代码片段。图是一个关于软件需要的重要沟通工具。图仅是正开发软件的是一个视图(投影)。它隐藏了许多的技术细节。动作是在图形表示外面增加技术细节的一个机制。一旦这个图放在这个位置,它可以被动作修饰。主要事件类型包含进入节点、离开节点和取得转换。

10.2. 流程图

流程定义的基础是由节点和转换组成的图。那信息被表达在一个叫prcessdefinition.xml的xml文件中。每个节点都有一个类型,如状态、决策、分支、合并等等,每个节点都有一系列的离开转换。为了区分开他们可以给转换一个名称。例如:下面的图显示的是jBAY拍卖流程的流程图:

图 10-1 拍卖流程图

下面是用使用xml表示的jBay的拍卖流程图:
<process-definition>
 
<start-state>

<transition to="auction" />

</start-state>

<state name="auction">

<transition name="auction ends" to="salefork" />

<transition name="cancel" to="end" />

</state>

<fork name="salefork">

<transition name="shipping" to="send item" />

<transition name="billing" to="receive money" />

</fork>

<state name="send item">

<transition to="receive item" />

</state>
 

<state name="receive item">

<transition to="salejoin" />

</state>

<state name="receive money">

<transition to="send money" />

</state>
 

<state name="send money">

<transition to="salejoin" />

</state>

<join name="salejoin">

<transition to="end" />

</join>

<end-state name="end" />

</process-definition>
 

10.3. 节点

一个流程图由节点和转换组成。更多的关于图和它的执行模型的信息,参考第4章 面向图的程序设计

每个节点有一个给定的类型。节点类型决定了在运行时当一个执行到达节点时将发生什么事情。你可以使用jBPM已经实现的一系列的节点类型。也许,你可以写自定义的代码来实现你自己的特定的节点行为。

10.3.1. Node职责

每一个节点有两个责任:首先,它可以执行一个纯java代码。典型地纯java代码同节点的功能是相关联。例如:创建一个新的任务实例、发送通知、更新数据库等等,其次,节点负责传播流程执行。基本上,每个节点为了传播流程执行有下列的选项:

·           1、不传播执行。那样的话这个节点相当于等待状态。

·           2、通过节点的离开转换中的一个来传播执行。这就意味着最初到达节点的令牌(token)使用API调用executionContext.leaveNode(String)方法通过其中的一个离开转换。这个节点将扮演一个自动节点,从某种意义上说,它可以执行一些定制的程序逻辑并且而后不用等待自动地继续流程执行。

·           3、创建新的执行路径。一个节点决定创建新的令牌。每个新令牌代表一个新的执行路径并且每个新令牌可以通过节点的离开转换被启动。这种行为相当的例子就是一个分支(fork)节点。

·           4、结束执行路径。节点能够决定执行路径的终点。那意味着令牌被结束并且执行路径被完成。

·           5、通常,节点可以修改整个流程实例的运行时结构。运行时结构是包含令牌树的一个流程实例。节点能够被创建并结束令牌、在图的一个节点上设置令牌以及通过转换启动令牌。

jBPM包含(像任何工作流和BPM引擎一样)一系列预实现的有明确的文档化配置和行为的节点类型。但关于jBPM和面向图的程序设计基础的唯一的事情是我们为开发人员展现了这样的模型。开发人员可以非常容易地写他们自己的节点行为以及在流程中使用它。

传统工作流和BPM系统更加封闭。他们通常提供一套固定的节点集合(叫流程语言)。它们的流程语言是封闭的并且执行模型是隐藏在运行时环境中。工作流模型的研究已经显示出任何的流程语言都不是足够强大的。我们选定了一个简单的模型并允许开发写自己的节点类型。那就是JPDL流程语言最后开放的途径。

下一步,我们将讨论下JPDL最重要的节点类型。

10.3.2. task-node节点类型

任务(task)节点代表一个或多个将要被人们执行的任务。所以当执行到达任务节点时,任务实例将在工作流参与者的任务列表中创建。后来,节点将相当于一个等待状态。所以当用户执行他们的任务时,任务完成将触发执行的恢复。换句话说,那将导致在令牌(token)上调用一个新的信号(signal)。

10.3.3. state节点类型

状态(state)节点是一个最基本的等待状态。同任务节点的不同是不会在任何任务列表中创建任务实例。如果流程要等待一个外部系统时是有用的。例如,在节点的入口上(通过一个在节点进入事件上的动作),一个消息可以被送到外部系统。在那之后,流程将进入等待状态。当这个外部系统发送一个响应消息时,这可以引起一个token.signal()方法,触发流程执行的恢复。

10.3.4. decision节点类型

实际上有两种方法来塑造决策(decision)。两种方法间的区别是由“谁”产生决策。应该是流程产生决策(读:规定在流程定义里),还是一个外部实体提供决策的结果。
当决策被流程产生时,决策节点应该被使用。有两个基本的方法去指定决策的条件。最简单的方式是在转换(trasitions)上增加条件元素。条件是EL表达式或beanshell脚本,它将返回一个布尔(boolean)值。
在运行时决策节点将“第一次”循环通过它的离开转换。那有一个指定的条件。它首先将顺序地计算那些在xml中指定的转换。第一个被解析为true的条件的那个转换将被处理。如果所有的都解析为false的话,缺省的转换(在XML中的第一个)被处理。

At runtime the decision node will FIRST loop over its leaving transitions THAT HAVE a condition specified. It will evaluate those transitions first in the order as specified in the xml. The first transition for which the conditions resolves to 'true' will be taken. If all transitions with a condition resolve to false, the default transition (the first in the XML) is taken.

另一种方案是使用一个表达式返回要处理转换的名称。关于表达式(expression)属性,你可以在决策上指定一个表达式必须解析到决策节点的一个离开转换中。

Another approach is to use an expression that returns the name of the transition to take. With the 'expression' attribute, you can specify an expression on the decision that has to resolve to one of the leaving transitions of the decision node.

下一个方案在决策上的“handler”元素,那个元素能够被用来指定一个已被指定在决策节点上的DecisionHandler接口的实现。然后决策在java类中被计算并通过DecisionHandler实现的决策方法返回选择的离开转换。

当决策被外部方(意思是:不是流程定义的部分)处理时,你应该使用多个转换离开一个状态或等待状态节点。然后离开转换能够被等待状态完成后恢复执行的外部的触发器提供。例如:Token.signal(String transitionName)和TaskInstance.end(String transitionName)。

10.3.5. fork节点类型

分叉(fork)节点分开一个执行路径成为多个并发的执行路径。缺省的分叉行为是为每个离开这个分叉节点的转换创建一个子令牌(token),在到达分叉节点时生成和这个令牌的一个父子关系(parent-child relation)。

10.3.6. join节点类型

缺省的,合并(join)假设所有到达合并节点的令牌是同一个父亲的孩子。这种情形被创建当使用上面所提及的分叉时创建同且当所有被分叉创建的令牌到达同一个合并时。一个合并将结束每一个进入合并的令牌。当所有的兄弟令牌已经到达合并时,父令牌将通过“唯一”的离开转换被传播。当仍然有兄弟令牌活动时,合并将扮演一个等待状态。

10.3.7. node节点类型

这一类型节点可用作你想在在节点中写自己的代码的这种情形。节点类型节点有一个子元素动作。这个动作在执行到达节点时被执行。你在actionhandler中写的代码可以做你完成的任何事,但是它也要 负责执行的传播
如果你想使用JavaAPI来实现一些对于业务分析来说是重要的功能逻辑的话,这个节点可被使用。由于使用节点,这个节点在流程图形表示中可见。作为比较,动作(下面要讲的)允许你增加代码,但它在流程图形表示中不可见,如果那样的话对于业务分析逻辑无关紧要。

10.4. 转换

转换(transitions)有一个源节点和一个目标节点。源节点代表来自(from)属性,目标节点代表到达(to)属性。

转换能够可选的来命名。注意jBPM的大部分属性依赖转换的命名的唯一性。如果有多个转换有相同的名称,第一个命名的转换将被处理。万一多个重复转换名称占用一个节点,方法Map getLeavingTransitionsMap()返回的元素要比List getLeavingTransitions()少。

缺省的转换是列表中的第一个转换。

10.5. 动作

动作(actions)是在流程执行里的事件上执行的java代码片段。图是关于软件需求沟通上一个重要的工具。而且图正好也是将要被开发的软件的一个视图(项目)。它隐藏了许多的技术细节。动作是在图形化表示外面增加技术细节的一个机制。一旦图放在那里,它可以被动作修饰。这就意味着在不改变图的结构的情况下可以让java代码同图关联起来。主要事件类型是进入节点(entering a node)、离开节点(leaving a node)和处理转换(taking a transition)。

注意下动作放在事件和放在节点上的不同。动作放在事件上当事件被触发时执行。事件上的动作没有办法去影响流程的控制流。它同观察者模式(observer pattern)很相似。另一方面,放置在节点上的动作有责任来传播执行

让我们看一个事件上动作的例子。假设我们想在给定的转换上执行一个数据库更新。数据库更新在技术上是至关重要的,但是对于业务分析就无关紧要了。

图 10-2 数据库更新动作

public class RemoveEmployeeUpdate implements ActionHandler {

public void execute(ExecutionContext ctx) throws Exception {

// 从流程变量上取得被操作的员工

String firedEmployee = (String) ctx.getContextInstance().getVariable("fired employee");

 

// 得到同jbpm更新使用的一样的同一个数据库连接,我们为我们的数据库更新
// 重用jbpm的事务
Connection connection = ctx.getProcessInstance().getJbpmSession().getSession().getConnection();

Statement statement = connection.createStatement();

statement.execute("DELETE FROM EMPLOYEE WHERE ...");

statement.execute();

statement.close();

}

}
 

<process-definition name="yearly evaluation">

 

...

<state name="fire employee">

<transition to="collect badge">

<action class="com.nomercy.hr.RemoveEmployeeUpdate" />

</transition>

</state>

 

<state name="collect badge">

...

 

</process-definition>
 

10.5.1. 动作配置

关于增加你自己的定制动作的配置和如何指定processdefinition.xml的配置的信息,请参考 21.2.3 代理配置

10.5.2. 动作引用

动作可以被命名。命名的动作能够被另一个可以指定动作的位置引用。命名的动作也能作为一个子元素放在流程定义中。
这个属性令人感兴趣的如果你想限制重复的动作配置的话(例如动作有一个复杂的配置)。另一个用例是执行或运行时动作调度。

10.5.3. 事件

事件指定片刻(moments)在流程执行里。jBPM引擎将触发事件在图执行期间。这将出现当jbpm计算下一状态时(请读:处理一个信号)。事件总是关联着流程定义元素(如流程定义、节点或转换)。大部分的流程元素都能用不同类型的事件触发。例如节点能触发节点进入事件和节点离开事件。事件挂在动作上。每个事件都有一个动作的列表。当jBPM引擎触发事件时,动作列表将被执行。

10.5.4. 事件传播

超级状态(Superstates)在流程定义元素里创建一个父子关系。包含在超级状态中的节点和转换把它当作父亲。上层元素把流程定义作为父亲,流程定义没有父亲。当一个事件被触发时,事件将向上传播到父层。这样就允许捕捉所有流程的转换事件及在一个中心位置同这些事件相关的动作。

10.5.5. 脚本

脚本(script)是一个动作执行的beanshell脚本。更多的关于beanshell的信息,请看beanshell网站。缺省情况下,所有流程变量可以当作脚本变量使用而且不会有脚本变量被写入流程变量中。下面的脚本变量是可用的:

  • executionContext
  • token
  • node
  • task
  • taskInstance
<process-definition>

<event type="node-enter">

<script>

System.out.println("this script is entering node "+node);

</script>

</event>

...

</process-definition>
为了定制缺省的加载行为了存储变量到脚本中,变量元素可以被用作脚本的子元素。那样的话,脚本表达式也会放进脚本的子元素:expression中。
<process-definition>

<event type="process-end">

<script>

<expression>

a = b + c;

</expression>

<variable name='XXX' access='write' mapped-name='a' />

<variable name='YYY' access='read' mapped-name='b' />

<variable name='ZZZ' access='read' mapped-name='c' />

</script>

</event>

...

</process-definition>
在脚本开始之前,流程变量YYY和ZZZ分别作为脚本变量b和c来用。在脚本完成后,脚本变量的值a被存储进流程变量XXX中。
如果访问变量属性包含“read”,那么流程变量将在脚本计算前作为脚本变量被加载。如果访问属性包含“write”,那么脚本变量将在计算后作为流程变量被存储。属性mapped-name能够让流程变量以脚本中的另一个名称来使用。这样可以很方便当你的流程变量命名中包含空格或其他的无效脚本字符(script-literal-characters)时。

10.5.6. 定制事件

注意也可能在流程执行期间触发你自自己的事件。事件通过图的组成元素(节点、转换流程定义和超级状态是图元素)以及事件类型(java.lang.String)唯一地定义。jBPM为节点、转换和其他的图元素定义一系列的触发事件。在动作中、自定义的节点实现中或甚至流程执行的外面,你可以调用GraphElement.fireEvent(String eventType, ExecutionContext executionContext);。事件类型的名称可以被自由的选择。

10.6. 超级状态

超级状态(superstate)是一组节点。超级状态可以递归地嵌套。超级状态常用来指出一些流程定义中的层次。例如:一个应用能够组合流程的所有节点成为了阶段。动作同超级状态事件相关联。结果是令牌可以在一个给定的时间被多重嵌套节点里。这是很方便的去检查是否流程执行在开始(start-up)阶段。在jBPM模型中,你可以在超级状态中自由地组合的任何节点集。

10.6.1. 超级状态转换

所有的转换离开一个超级状态都能够被超级状态所包含的节点里的令牌处理。转换也能到达超级状态。那样的话,令牌将重定位超级状态的第一个节点。超级状态外面的节点有转换直接地到内部节点。而且,与之相反,超级状态内部节点有转换到外部节点或到超级状态自身。超级状态也可以有自己的引用。

10.6.2. 超级状态事件

超级状态有两个唯一的事件:超级状态进入(superstate-enter)和超级状态离开(superstate-leave。这些事件都将被触发无论是通过各自的节点进入或离开转换。只要令牌在超级状态的内部处理转换,这些事件就不会被触发。
注意我们已经为状态和超级状态创建了独立的事件类型。这就使它变得容易了,区分从超级状态内部传播出的超级状态事件和节点事件。

10.6.3. 分层命名

节点名称在它们的范围内必须是唯一的。节点的范围是它的节点集合(node-collection)。流程定义和超级状态都是节点的集合。为了在超级状态中引用节点,你必须指定相对、正斜线(/)分隔的名称。斜线分隔节点名称。使用“..”引用上级。下个例子显示了如何在超级状态中引用一个节点:
<process-definition>

...

<state name="preparation">

<transition to="phase one/invite murphy"/>

</state>

<super-state name="phase one">

<state name="invite murphy"/>

</super-state>

...

</process-definition>
下个例子显示了如何建立超级状态的级别。
<process-definition>

...

<super-state name="phase one">

<state name="preparation">

<transition to="../phase two/invite murphy"/>

</state>

</super-state>

<super-state name="phase two">

<state name="invite murphy"/>

</super-state>

...

</process-definition>

10.7. 异常处理

jBPM异常处理机制只应用于java异常。图执行在它自己上面不会导致问题。它只是能够导致异常的代理类(delegation classes)的执行。
在流程定义、节点和转换上,指定了一列异常处理(exception-handlers)。每个异常处理有一列动作。当在代理类中发生异常时,这个流程元素的父亲层次会搜索一个合适的异常处理。当它被找到后,异常处理的动作被执行。
注意jBPM的异常处理机制同java的异常处理不完全相似。在java中,一个被捕捉的异常对控制流会有影响。就jBPM来说,控制流不能通过jBPM异常处理机制来改变。异常要么被捕获要么没有。没有被捕获的异常被抛出到客户端(例如:调用token.signal()的客户端),要么异常就被jBPM异常处理捕获。对于捕获的异常,图执行继续就像没有异常一样。

注意在一个处理异常的动作里,它可能使用Token.setNode(Node node)方法来放置这个令牌在图的任意一个节点上。

10.8. 流程组成

流程组成借助流程状态(process-state)的在jBPM中被支持。流程状态是一个同另一个流程定义关联的状态。当图执行到达流程状态时,一个子流程的新流程实例被创建并且同在流程状态上到达的执行路径相关联。超级流程(super process)的执行路径将等待直到子流程实例已经结束。当子流程实例结束时,超级流程执行路径将离开流程状态并继续超级流程里的图执行。

<process-definition name="hire">

<start-state>

<transition to="initial interview" />

</start-state>

<process-state name="initial interview">

<sub-process name="interview" />

<variable name="a" access="read,write" mapped-name="aa" />

<variable name="b" access="read" mapped-name="bb" />

<transition to="..." />

</process-state>

...

</process-definition>

这个hire流程包含一个产生interview流程的流程状态。当执行到达“first interview”时,一个 interview流程的新的执行(=process instance)被创建。如果没有明确版本被指定,当部署hire流程时已知子流程的最新版本将被使用。为了让jBPM实例化一个特定版本,可选的版本属性可以被指定。为了延迟绑定指定的或最新的版本直到真正创建子流程时,可选的绑定属性应该被设置为late。然后hire流程的变量“a”被复制进入interview流程的变量“aa”中。同样的方法,hire流程的变量“b”被复制进入interview流程的变量“bb”中。当interview流程完成时,只有interview流程的变量“aa”被复制回hire流程的变量“a”中。

通常,当一个子流程开始时,所有的读访问(read access)变量从超级流程中读取并在signal被给予离开开始状态前输入新创建的子流程中。当子流程实例被完成时,所有的写访问(write access)变量将从子流程变量复制到超级流程中。变量元素的映射名称(mapped-name)属性允许你去指定应该在子流程中使用的变量名称。

10.9. 定制节点行为

在jBPM中,它是非常容易的去写你自定义和节点。对于创建自定义节点,一个ActionHandler的实现已经被写完,这个实现可以执行任何的业务逻辑,但也负责去传播图执行。让我们看一个更新ERP系统的例子。我们将从ERP系统中读一个数量,增加一个存储在流程变量中的数量然后再存这个结果回到ERP系统中。基于数量的大小,我们不得不通过“小额”和“大额”离开转换离开这个节点。

图 10-3 更新ERP例子的流程片段

public class AmountUpdate implements ActionHandler {

public void execute(ExecutionContext ctx) throws Exception {

// 业务逻辑
Float erpAmount = ...从ERP系统中获取数量...;

Float processAmount = (Float) ctx.getContextInstance().getVariable("amount");

float result = erpAmount.floatValue() + processAmount.floatValue();

...update erp-system with the result...;

// 图执行传播
if (result > 5000) {

ctx.leaveNode(ctx, "big amounts");

} else {

ctx.leaveNode(ctx, "small amounts");

}
}
}

它也可能创建并合并令牌在定制的节点实现里。就如何做这个的例子,到jbpm源代码检出Fork和Join节点实现吧 :-)。

10.10. 图执行

jBPM的图执行模型是基于流程定义解析和命令模式链(chain of command pattern)。流程定义解析意味流程定义数据被存储在数据库中。在运行时流程定义信息在流程执行期间被使用。注意相关的,我们使用hibernate的二级缓存去避免在运行时定义信息的加载。因为流程定义不能改变(查看流程版本管理(process versioning)),所以hibernate能够在内存中缓存流程定义。
命令链模式意味着图的每个节点负责传播流程执行。如果某个节点不传播执行的话,那么它相当于一个等待状态。
这个想法是在流程实例上开始执行而且那个执行继续直到它进入一个等待状态。
一个令牌代表执行的路径。一个令牌在流程图中有一个指向节点的指针。在等待状态期间,这个令牌能够被持久化在数据库中。现在我们要看一下计算令牌执行的算法。执行当一个信号被送到令牌时开始,执行然后传递转换和节点通过命令链模式。这些是在一个类图中的相关的方法。

图 10-4 图执行的相关方法

当令牌是在一个节点上时,信号能够被送到令牌上。发送一个信号是一个开始执行的指令。一个信号因此必须指定令牌的当前节点的离开转换。第一个转换是缺省的。在一个信号到达令牌上,令牌处理它的当前节点并调用Node.leave(ExecutionContext,Transition)方法。认为ExecutionContext是令牌因为在ExecutionContext中的主要对象是一个令牌。Node.leave(ExecutionContext,Transition)方法将触发转换事件并在转换的目标结点上调用Node.enter(ExecutionContext)方法。那个方法将触发节点进入事件并且调用 Node.execute(ExecutionContext)方法。每一节点类型都有它自己的在execute方法中实现的行为。每一个节点通过再次调用Node.leave(ExecutionContext,Transition)方法负责传播图执行。综上所述:
  • Token.signal(Transition)
  • --> Node.leave(ExecutionContext,Transition)
  • --> Transition.take(ExecutionContext)
  • --> Node.enter(ExecutionContext)
  • --> Node.execute(ExecutionContext)
注意下一个状态的完全计算,包含在客户端的线程里的动作调用完成。通常的误解是在客户端的线程的所有计算必须被完成。与异步调用一样,你可以使用异步消息(JMS)来完成那些。当消息在与流程实例更新相同的事务里被发送时,所有同步问题被处理。某些工作流系统在图的所有节点间使用异步消息。但在高吞吐量的环境中,这个算法为调整业务流程的性能提供了更多的控制和灵活性。

10.11. 事务划分

同样的解释在10.10 图执行部分和第4章 面向图的程序设计,jBPM在客户端线程中运行流程而且天生就是同步的。那意味着token.signal()或taskInstance.end()当流程已经进入新的等待状态时将只是返回。

我们这里描述的jPDL属性是来自第15章 异步连续的建模视图。

在大部分情形下这是最直接的方案,因为流程执行可以容易地也必然是有服务器端事务:在一个事务中流程从一个状态移动到下一个状态。
在一些场景里的流程内部计算花费许多时间,这个行为也许是令人讨厌的。了为应付这个问题,jBPM包括一个异步消息系统,它允许以一种异步的方式继续流程。当然,在java企业环境里,jBPM能够被配置为使用JMS消息中间件(broker)取代内置的消息系统。
在任一节点里,jPDL支持属性async="ture"。异步节点将不被姓在客户端线程中,一个消息通过异步消息系统被发送而且线程返回到客户端(意味着token.signal()或taskInstance.edn()将返回)。
注意jbpm客户端代码能够现在提交事务。正在发送的消息应该在和流程更新相同的同一个事务中完成。所以事务的最终结果是令牌已经移动到下一个节点(还没有被执行的)并且一个 org.jbpm.command.ExecuteNodeCommand消息已经在异步消息系统上被发送jBPM命令执行器。
jBPM命令执行器从队列中读取命令并执行他们。就 org.jbpm.command.ExecuteNodeCommand来说,流程将依赖在一个独立的事务中 执行的node. Each命令而被 继续
所以为了使异步流程继续,jBPM命令执行器需要运行。最简单的方式是在你的web应该中配置 CommandExecutionServlet,作为选择,你应该确信CommandExecutor线程是启动并以任何其他的方式在运行。
作为一个流程建模人员,你不应该太在意所有的异步消息。 主要暗示记住界限:缺省jBPM将在客户端事务中操作,执行整个的计算直到流程进入一个等待状态。使用ansync="true"来划分流程中的一个事务。
让我们看一个例子:
...
<start-state>

<transition to="one" />

</start-state>

<node async="true" name="one">

<action class="com...MyAutomaticAction" />

<transition to="two" />

</node>

<node async="true" name="two">

<action class="com...MyAutomaticAction" />

<transition to="three" />

</node>

<node async="true" name="three">

<action class="com...MyAutomaticAction" />

<transition to="end" />

</node>

<end-state name="end" />

...
客户端代码同流程执行的交互(开始和恢复)是同正常(同步)流程绝对相同的:

...start a transaction...

JbpmContext jbpmContext = jbpmConfiguration.createContext();

try {

ProcessInstance processInstance = jbpmContext.newProcessInstance("my async process");

processInstance.signal();

jbpmContext.save(processInstance);

} finally {

jbpmContext.close();

}
在第一个事务后,流程实例根令牌指到节点one并且一个ExecuteNodeCommandmessage被送到命令执行器。
在随后的事务里,命令执行器将从队列中读消息并执行节点one。动作可以决定是传播执行还是进入等待状态。如果动作决定传播执行,当执行到达节点two时事务将被结束,等等,等等……
 
海绵中的水还是可以挤的呀,昨天少少的加了一个班,完成了这章的翻译,传上来了
继续吧.....
:-)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值