jBPM-4.0中文开发指南-第13章执行模式

第 13 章 执行模式

这里有三种基本的流程执行模式:对象,持久化和嵌入。 对于持久化和嵌入执行模式, 流程执行必 须在一个事务中执行。在那种情况, 流程执行必须放在一个环境的内部。 环境将用来绑定流程执行,更 新到一个应用事务的事务中。 环境可以被用来绑定,比如一个JDBC连接, JTA,BMT,Spring事务等等。

13.1. 对象执行模式

对象执行模式是使用流程虚拟机的最简单形式。 这意味着通过客户端API直接使用流程定义和执行对 象。 让我们通过一个例子演示这个。 我们通过创建一个ClientProcessDefinition开始,看起来像这样 :

对象执行模式是使用流程虚拟机的最简单形式。 这意味着通过客户端API直接使用流程定义和执行对 象。 让我们通过一个例子演示这个。 我们通过创建一个ClientProcessDefinition开始,看起来像这样 :

图 13.1. 贷款流程

ClientProcessDefinition processDefinition = ProcessFacTory.build("loan")  .activity("submit loan request").initial().behaviour(AutomaticActivity.class)    .transition().to("evaluate")  .activity("evaluate").behaviour(WaitState.class)     .transition("approve").to("wire money")    .transition("reject").to("end")  .activity("wire money").behaviour(AutomaticActivity.class)    .transition().to ("archive")  .activity("archive").behaviour(WaitState.class)    .transition ().to("end")  .activity("end").behaviour(WaitState.class).done();

ProcessFacTory是一个帮助类, 为构建一个表现为流程定义的对象图提供方便。 AutomaticActivity 是一个通过活动, 没有任何操作发生,WaitState会等到外部signal发生。 这两个活动实现都会在后面 讨论更深。

processDefinition对象作为一个工厂,为流程实例对象。 一个流程实例表现为流程定义的一个执行 。 更准确的说,流程实例是执行的主路径。

ClientExecution execution = processDefinition.startProcessInstance();

一个流程实例自己也是一个Execution. 潜在的,一个执行可以拥有子执行 表现执行的同步路径。

execution可以看做是一个状态机, 在流程定义里像描述一样操作。启动一个流程实例意思是 流程定 义的初始节点被执行。 因为这是一个自动活动,执行会执行到evaluate活动。 evaluate活动是一个等待 状态。 当执行到达evaluate活动,startProcessInstance方法 会返回并等待一个外部signal使用signal 方法提供。 所以在startProcessInstance之后,我们可以证实 如果执行定位在evaluate活动。

assertEquals(“evaluate”, execution.getActivityName());

为了让流程执行得更远,我们提供一个外部触发器使用 signal方法。执行的结果会被作为 signalName参数给与,像这样:

execution.signal(“approve”);

WaitState活动实现会根据给出的signalName 选择转移。所以执行将首先执行自动活动wire money 然 后在进入等待状态archive后 返回。

assertEquals(“archive”, execution.getActivityName());

当执行在archive活动等待时,默认的signal会让它 选择第一个未命名的转移。

execution.signal();assertEquals("end", execution.getActivityName());

流程执行在客户端的线程中。 startProcessInstance方法只在到达evaluate活动时返回。 换句话说 ,ClientProcessDefinition.startProcessInstance和 ClientExecution.signal方法会一直堵塞直到 下 一个等待状态的到来。

13.2. 持久化执行模式

流程虚拟机也包含hibernate映射来保存流程定义和执行 在任何数据库中。一个特定的会话外观叫做 ExecutionService 被提供给流程执行 在这样一个持久化环境中。

两个配置文件应该放在classpath下:一个环境配置文件 和一个hibernate.properties文件。 一个持 久化执行模式的基础配置,在一个标准Java环境 看起来像这样:

environment.cfg.xml:

                                                                                                                                                                                                       

下一个,hibernate.properties像这样:

hibernate.properties:

hibernate.dialect                      org.hibernate.dialect.HSQLDialecthibernate.connection.driver_class      org.hsqldb.jdbcDriverhibernate.connection.url               jdbc:hsqldb:mem:.hibernate.connection.username          sahibernate.connection.passwordhibernate.hbm2ddl.auto                  create-drophibernate.cache.use_second_level_cache truehibernate.cache.provider_class         org.hibernate.cache.HashtableCacheProvider# hibernate.show_sql                      truehibernate.format_sql                   truehibernate.use_sql_comments             true

然后你可以从环境工厂中像这样获得服务:

EnvironmentFacTory environmentFacTory = new PvmEnvironmentFacTory ("environment.cfg.xml");ProcessService processService = environmentFacTory.get (ProcessService.class);ExecutionService executionService = environmentFacTory.get (ExecutionService.class);ManagementService managementService = environmentFacTory.get (ManagementService.class);

ProcessService的责任是管理流程定义资源。 在我们可以启动一个流程执行之前, 流程定义需要被 发布到流程资源库中。 流程定义可以使用不同的格式和不同的流程语言提供。 一个发布包含了流程定义 信息,从不同的源文件中,像一个ZIP文件, 一个XML文件或一个流程定义对象。 ProcessService.deploy方法会获得一个发布 通过配置在配置文件里的所有发布器。

在这个例子中,我们通过代码方式为发布 提供一个流程定义。

ClientProcessDefinition processDefinition = ProcessFacTory.build("loan")  .activity("submit loan request").initial().behaviour(AutomaticActivity.class)    .transition().to("evaluate")  .activity("evaluate").behaviour(WaitState.class)     .transition("approve").to("wire money")    .transition("reject").to("end")  .activity("wire money").behaviour(AutomaticActivity.class)    .transition().to ("archive")  .activity("archive").behaviour(WaitState.class)    .transition ().to("end")  .activity("end").behaviour(WaitState.class).done();Deployment deployment = new Deployment(processDefinition);processService.deploy(deployment);

现在流程定义的一个版本保存到数据库中。 check-version发布器会把版本1 分配给存储的流程定义 。create-id发布器 会提取idloan:1 根据流程名称和分配的版本。

再次发布流程会导致在数据库中创建一个新流程定义。 但是一个增加的版本数会被分配。 出于版本 化的目的,如果有相同的名字, 流程定义就会相同。

推荐用户为所有流程执行提供key的引用。 启动一个新流程执行像这样:

Execution execution = executionService.startExecution(“loan:1”, “request7836”);

返回值是一个execution接口,防止关系的向导。 那是因为服务方法外面,事务和hibernate会话没有 保证一直打开。 实际上,上面给出的默认的配置只保证 事务和会话在服务方法执行中是打开的。 所以 服务方法外的关系导航可能引起一个hibernate的 LazyInitializationException. 但是当前的活动名称 还可以被验证。

assertEquals(“evaluate”, execution.getActivityName());

生成可以被获得的id也是非常重要的。 默认的id-generaTor会用来生成流程定义的id 给出的key来为 流程执行生成一个唯一id,像这样:

assertEquals(“loan:1/request7836”, execution.getId());

那个id必须提供给外部触发器 像这样处理流程执行:

executionService.signalExecution(“loan:1/request7836”, “approve”);

关于服务接口的更多信息,关于如何运行在持久化模式下, 可以在包 org.jbpm.pvm 的api doc找到 。

13.3. 嵌入执行模式

嵌入执行模式意味着路程的状态保存在 一个用户领域对象的字符串列中,比如一个loan.

public class Loan {  /** the loan process definition as a static resource */  private static final ClientProcessDefinition processDefinition = createLoanProcess ();  private static ClientProcessDefinition createLoanProcess() {    ClientProcessDefinition processDefinition = ProcessFacTory.build("loan")      .activity("submit loan request").initial().behaviour(AutomaticActivity.class)         .transition().to("evaluate")      .activity("evaluate").behaviour (WaitState.class)        .transition("approve").to("wire money")         .transition("reject").to("end")      .activity("wire money").behaviour (AutomaticActivity.class)        .transition().to("archive")      .activity("archive").behaviour(WaitState.class)        .transition().to("end")       .activity("end").behaviour(WaitState.class)    .done();    return processDefinition;  }  /** exposes the process definition to the execution hibernate type */  private static ClientProcessDefinition getProcessDefinition() {    return processDefinition;  }  long dbid;  String customer;  double amount;  ClientExecution execution;  /** construcTor for persistence */  protected Loan() {  }  public Loan (String customer, double amount) {    this.customer = customer;    this.amount = amount;    this.execution = processDefinition.startProcessInstance();  }   public void approve() {    execution.signal("approve");  }  public void reject() {    execution.signal("reject");  }  public void archiveComplete() {    execution.signal();  }  public String getState() {    return execution.getActivityName();  }  ...getters...}

如果你暂时忽略加粗部分,你可以看到这是一个没有任何奇异的POJO. 它只是一个bean,可以保存到 hibernate中。 粗体部分展示了类的实现部分,这与流程和执行相关。 流程定义或者执行都没有暴露给 Loan类的用户。

每个Loan对象对应一个loan流程实例。 Loan类的一些方法 对应外部触发器, 这会在Loan对象的生命 周期被触发。

接下来我们演示如何使用这个类,为了开始,我们需要一个

hibernate.cfg.xml:

       org.hibernate.dialect.HSQLDialect    org.hsqldb.jdbcDriver    jdbc:hsqldb:mem:.    sa        create    true"    true"    true"     

和一个

Loan.hbm.xml:

<?xml version="1.0"?<<!DOCTYPE hibernate-mapping PUBLIC           "-//Hibernate/Hibernate Mapping DTD 3.0//EN"          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"<<hibernate- mapping package="org.jbpm.pvm.api.db.embedded" default-Access="field"<    <class name="Loan" table="LOAN"<    <id name="dbid"<          </id<              </class<</hibernate-mapping<

然后你可以在测试中像这样使用Loan类

Configuration configuration = new Configuration();configuration.configure ();SessionFacTory sessionFacTory = configuration.buildSessionFacTory();// start a session/transactionSession session = sessionFacTory.openSession();Transaction transaction = session.beginTransaction();Loan loan = new Loan("john doe", 234.0);session.save(loan);assertEquals("evaluate", loan.getState());// start a new session/transactiontransaction.commit();session.close();session = sessionFacTory.openSession();transaction = session.beginTransaction();loan = (Loan) session.get(Loan.class, loan.getDbid());assertEquals("evaluate", loan.getState ());loan.approve();assertEquals("archive", loan.getState());// start a new session/transactiontransaction.commit();session.close();

在执行这段代码之后,这是在数据库中的loan记录:

图 13.2. 数据库中的贷款记录

爱情要完结的时候自会完结,到时候,你不想画上句号也不行。

jBPM-4.0中文开发指南-第13章执行模式

相关文章:

你感兴趣的文章:

标签云: