第1章介绍
JBOSS jBPM是一个灵活的、可扩展的工作流管理系统。JBOSS jBPM拥有直观的流程语言,用任务、异步的等待状态、定时器、自动化动作…等来表示业务流程图,把这些操作绑定在一起,JBOSS jBPM就拥有了非常强大和可扩展的控制流机制。
JBOSS jBPM只有最小的依赖,可以象使用java库一样非常容易的使用它。另外,也可以通过把它部署在J2EE集群应用服务器中,用在吞吐量极为关键的环境中。
JBOSS jBPM可被配置为任何数据库,并且可以部署到任何应用服务器。
1.1 概述
核心工作流和BPM功能被打包为一个简单的java库,这个库包括一个存储到数据库、从数据库更新和获取流程信息的服务。
图1.1 JBOSS jBPM组件概观
1.2 JBOSS jBPM入门套件
入门套件是一个包含了所有jBPM组件的下载包,包括:
l Jbpm-server,一个预配置好的jboss应用服务器。
l Jbpm-designer,图形化设计jBPM流程的eclipse插件。
l Jbpm-db,jBPM数据库兼容包(见下文)。
l Jbpm,核心jbpm组件,包括库和本指南。
l Jbpm-bpel,JBOSS jBPM BPEL扩展参考。
预配置好的JBOSS应用服务器安装了下列组件:
l核心的jBPM组件,被打包为了一个服务档案。
l一个包括jBPM库表的集成数据库:默认的hypersonic数据库包含了jBPM表,另外还包含一个流程。
l jBPM控制台web应用程序,可以由流程参与者使用,也可以由jBPM管理员使用。
l jBPM调度程序,用于定时器执行。调度程序在入门套件中被配置为一个servlet,这个servlet 将产生一个线程来监视和执行定时器。
l jBPM命令执行器,用于命令的异步执行。命令执行器也被配置为一个servlet,这个servlet 将产生一个线程来监视和执行命令。
l一个流程实例,已经被部署到了jBPM数据库中。
1.3 JBOSS jBPM图形化流程设计器
JBOSS jBPM还包括一个图形化设计工具,这个设计器是一个创作业务流程的图形化工具。
JBOSS jBPM图形化流程设计器是一个eclipse插件,可以独立安装的设计器已经在开发目标中。
图形化设计器非常重要的特性是它同时支持业务分析者和技术开发者,这使的业务流程建模可以平滑的转换到实际实现。
插件可以被用作本地更新设置(普通的zip文件),通过标准的eclipse软件更新机制安装。另外还有一个包,你可以直接把它解压到eclipse主目录里。
1.4 JBOSS jBPM核心组件
JBOSS jBPM核心组件是普通java(J2SE)软件,用来管理流程定义和流程实例执行的运行时环境。
JBOSS jBPM是一个java库,因此,它可以被用在任何java环境,例如web应用、swing 应用、EJB、webservice…等,jBPM库还可以被打包为无状态会话EJB,这允许被作为集群部署,并且适用于极高的吞吐量。无状态会话EJB按照J2EE1.3规范编写,因此它可以部署到任何应用服务器。
JBOSS jBPM核心组件被打包为一个简单的java库文件,依赖于你所使用的功能,jbpm-3.0.jar库对第三方库有些依赖,如hibernate、dom4j和其他,这些在“第5章部署”TODO中有清晰的说明。
为了持久化,jBPM内部使用hibernate,除了传统的O/R影射之外,hibernate还解决了不同数据库之间的SQL方言(dialect)问题,使jBPM可以方便的在当前所有数据库上移植。
JBOSS jPBM API可以从你的项目中任何定制的java软件中访问,例如你的web应用、你的EJB、你的webservice组件、你的消息驱动bean,或者其他java组件。
1.5 JBOSS jBPM控制台web应用程序
jBPM控制台web应用程序服务于两个目的。首先,它作为与由流程执行所产生的运行时任务相交互的一个重要的用户接口;其次,它是一个管理和监控控制台,允许检查和操纵运行时实例。
1.6 JBOSS jBPM身份组件
JBOSS jBPM可以与任何包含用户或其他组织信息目录的公司集成,但是对于没有组织信息组件可用的项目,JBOSS jBPM包含了它自己的组件。身份组件所使用的模型比传统的
servlet、ejb和portlet(译者注:portlet是portal中最重要的组件,与servlet类似,portlet 是部署在容器中用来生成动态内容的web组件。)模型更丰富。
更多信息,请看“11.11 身份组件”。TODO
1.7 JBOSS jBPM调度程序
JBOSS jBPM调度程序是一个用来监视和执行定时器的组件,它在流程执行期间被调度。
定时器组件软件被打包进核心的jbpm库,但是它需要被部署进下列环境之一:要么配置调度程序servlet去产生监视线程,要么用调度程序的main方法启动一个独立的JVM。1.8 JBOSS jBPM数据库兼容包
JBOSS jBPM数据库兼容包是一个包含能使jBPM在你所选择的数据库上运行的所有信息、驱动程序和脚本的下载包。
1.9 JBOSS jBPM BPEL扩展
JBOSS jBPM BPEL 扩展是一个独立的扩展包,它扩展了jBPM,使之支持BPEL(Business Process Execution Language商业流程执行语言),BPEL本质上是一个xml脚本语言,用来根据其他web服务(web services)编写web 服务(web services)。
第3章指南
这个指南将向你展示如何用jpdl创建基本的流程以及如何使用API管理运行期的执行。
这个指南的形式是解释一组示例,每个示例集中于一个特殊的主题,并且包含大量的注释,这些例子也可以在jBPM下载包的目录src/java.examples中找到。
最好的学习方法就是建立一个工程,并且通过在给定例子上做不同的变化进行实验。
对eclipse用户来说可以如下方式开始:下载jbpm-3.0-[version].zip并且解压到自己的系统,然后执行菜单“File”-->“Import…”-->“Existing Project into Workspace”,然后点击“Next”,浏览找到jBPM根目录,点击“Finish”。现在,在你的工作区中就有了一个jbpm.3工程,你可以在src/java.examples/…下找到本指南中的例子,当你打开这些例子时,你可以使用菜单“Run”-->“Run As…”-->“JUnit Test”运行它们。
jBPM包含一个用来创作例子中展示的XML的图形化设计器工具,你可以在“2.1 下载概述”中找到这个工具的下载说明,但是完成本指南不需要图形化设计器工具。
3.1 Hello World 示例
一个流程定义就是一个有向图,它由节点和转换组成。Hello world流程有三个节点,下面来看一下它们是怎样组装在一起的,我们以一个简单的流程作为开始,不用使用设计器工具,下图展示了hello world流程的图形化表示:
图3.1 hello world流程图
public void testHelloWorldProcess() {
// 这个方法展示了一个流程定义以及流程定义的执行。
// 这个流程定义有3个节点:一个没有命名的开始状态,
// 一个状态“s”,和一个名称为“end”的结束状态。
// 下面这行是解析一段xml文本到ProcessDefinition对象(流程定义)。// ProcessDefinition把一个流程的规格化描述表现为java对象。
ProcessDefinition processDefinition =
ProcessDefinition.parseXmlString(
"
"
"
" " +
"
"
" " +
"
""
);
// 下面这行是创建一个流程定义的执行。创建后,流程执行有一个
// 主执行路径(=根令牌),它定位在开始状态。
ProcessInstance processInstance =
new ProcessInstance(processDefinition);
// 创建后,流程执行有一个主执行路径(=根令牌)。
Token token = processInstance.getRootToken();
// 创建后,主执行路径被定位在流程定义的开始状态。
assertSame(processDefinition.getStartState(), token.getNode());
// 让我们开始流程执行,通过它的默认转换离开开始状态。
token.signal();
// signal方法将会把流程阻塞在一个等待状态。
// 流程执行进入第一个等待状态“s”,因此主执行路径现在定位
// 在状态“s”。
assertSame(processDefinition.getNode("s"), token.getNode());
// 让我们发送另外一个信号,这将通过使用状态“s”的默认转换
// 离开状态“s”,恢复流程执行。
token.signal();
// 现在signal方法将返回,因为流程示例已经到达结束状态。
assertSame(processDefinition.getNode("end"), token.getNode()); }
3.2 数据库示例
jBPM的特性之一就是在流程等待状态时,拥有把流程的执行持久化到数据库中的能力。下面的例子将向你展示怎样存储一个流程实例到数据库,例子中还会出现上下文。分开的方法被用来创建不同的用户代码,例如,一段代码在web应用中启动一个流程并且持久化执行到数据库,稍后,由一个消息驱动bean从数据库中加载流程实例并且恢复它的执行。
有关jBPM持久化的更多信息可以在“第7章持久化”找到。
public class HelloWorldDbTest extends TestCase {
static JbpmConfiguration jbpmConfiguration = null;
static {
// 在“src/config.files”可以找到象下面这样的一个示例配置文件。
// 典型情况下,配置信息在资源文件“jbpm.cfg.xml”中,但是在这里// 我们通过XML字符串传入配置信息。
// 首先我们创建一个静态的JbpmConfiguration。一个JbpmConfiguration
// 可以被系统中所有线程所使用,这也是为什么我们可以把它安全的设置// 为静态的原因。
jbpmConfiguration = JbpmConfiguration.parseXmlString(
"
//jbpm-context机制分离了jbpm核心引擎和来自于外部环境的服务。
"
" " factory='org.jbpm.persistence.db.DbPersistenceServi ceFactory' />" + " " + // 同样,jbpm使用的所有资源文件在jbpm.cfg.xml中被提供。 " " value='hibernate.cfg.xml' />" + " " value='org/jbpm/calendar/jbpm.business.calendar.prop erties' />" + " " value='org/jbpm/graph/def/jbpm.default.modules.prop erties' />" + " " value='org/jbpm/db/hibernate/jbpm.converter.properti es' />" + " " value='org/jbpm/graph/action/action.types.xml' />" + " " value='org/jbpm/graph/node/node.types.xml' />" + " " value='org/jbpm/context/exe/jbpm.varmapping.xml' />" + "" ); } public void setUp() { jbpmConfiguration.createSchema(); } public void tearDown() { jbpmConfiguration.dropSchema(); } public void testSimplePersistence() { // 在下面调用的3个方法之间,所有的数据通过数据库被传递。 // 在这个测试中,这3个方法被依次执行,因为我们想要测试一个 // 完整的流程情景。但是实际上,这些方法表示了对服务器的不同 // 请求。 // 因为我们以一个干净的空数据库开始,所以我们首先必须部署流程。 // 事实上,这只需要由流程开发者做一次。 deployProcessDefinition(); // 假设在一个web应用中当用户提交一个表单时我们起动一个流程 // 实例(=流程执行)… processInstanceIsCreatedWhenUserSubmitsWebappForm(); // 然后,一个异步消息到达时继续执行。 theProcessInstanceContinuesWhenAnAsyncMessageIsReceived(); } public void deployProcessDefinition() { // 这个测试展示了一个流程定义以及流程定义的执行。 // 这个流程定义有3个节点:一个没有命名的开始状态, // 一个状态“s”,和一个名称为“end”的结束状态。 ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( " " " " " + " " " " + " "" ); // 查找在上面所配置的pojo持久化上下文创建器。 JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { // 部署流程定义到数据库中。 jbpmContext.deployProcessDefinition(processDefinition); } finally { // 关闭pojo持久化上下文。这包含激发(flush)SQL语句把流程// 定义插入到数据库。 jbpmContext.close(); } } public void processInstanceIsCreatedWhenUserSubmitsWebappForm() { // 本方法中的代码可以被放在struts的actiong中,或JSF管理 //的bean中。 //查找在上面所配置的pojo持久化上下文创建器。 JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { GraphSession graphSession = jbpmContext.getGraphSession(); ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition("hello world"); // 使用从数据库中获取的流程定义可以创建一个流程定义的执行 // 就象在hello world例子中那样(该例没有持久化)。 ProcessInstance processInstance = new ProcessInstance(processDefinition); Token token = processInstance.getRootToken(); assertEquals("start", token.getNode().getName()); // 让我们起动流程执行 token.signal(); // 现在流程在状态's'。 assertEquals("s", token.getNode().getName()); // 现在流程实例processInstance被存储到数据库, // 因此流程执行的当前状态也被存储到数据库。 jbpmContext.save(processInstance); // 以后我们可以从数据库再取回流程实例,并且通过提供另外一个 // 信号来恢复流程执行。 } finally { // 关闭pojo持久化上下文。 jbpmContext.close(); } } public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() { // 本方法中的代码可以作为消息驱动bean的内容。 // 查找在上面所配置的pojo持久化上下文创建器。 JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { GraphSession graphSession = jbpmContext.getGraphSession(); // 首先,我们需要从数据库中取回流程实例。 // 有几个可选方法来分辨出我们在这里所要处理的流程实例。 // 在这个简单的测试中,最容易的方式是查找整个流程实例列表, // 这里它应该只会给我们一个结果。 // 首先,让我们查找流程定义。 ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition("hello world"); // 现在我们搜索这个流程定义的所有流程实例。 List processInstances = graphSession.findProcessInstances(processDefinition.getId() ); // 因为我们知道在这个单元测试中只有一个执行。 // 在实际情况中, 可以从所到达的信息内容中提取processInstanceId // 或者由用户来做选择。 ProcessInstance processInstance = (ProcessInstance) processInstances.get(0); // 现在我们可以继续执行。注意:processInstance 将委托信号 // 到主执行路径(=根令牌)。 processInstance.signal(); // 在这个信号之后,我们知道流程执行应该到达了结束状态。 assertTrue(processInstance.hasEnded()); // 现在我们可以更新数据库中的执行状态。 jbpmContext.save(processInstance); } finally { // 关闭pojo持久化上下文。 jbpmContext.close(); } } } 3.3 上下文示例:流程变量 流程变量包含了流程执行期间的上下文信息,流程变量与一个java.util.Map相似,它影射变量名称和值,值是java对象,流程变量作为流程实例的一部分被持久化。为了让事情简单,在这里的例子中我们只是展示使用变量的API,而没有持久化。 有关变量的更多信息可以在“第10章上下文”中找到。 // 这个例子仍然从hello world流程开始,甚至没有修改。ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( " " " " " + " " " " + " "" ); ProcessInstance processInstance = new ProcessInstance(processDefinition); // 从流程实例获取上下文实例,用来使用流程变量。 ContextInstance contextInstance = processInstance.getContextInstance(); // 在流程离开开始状态之前,我们要在流程实例的上下文中 // 设置一些流程变量。 contextInstance.setVariable("amount", new Integer(500)); contextInstance.setVariable("reason", "i met my deadline"); // 从现在开始,这些流程变量与流程实例相关联。现在展示由用户代码通过// API访问流程变量,另外,这些代码也可以存在于动作或节点的实现中。// 流程变量被作为流程实例的一部分也被存储到数据库中。processInstance.signal(); // 通过contextInstance访问流程变量。 assertEquals(new Integer(500), contextInstance.getVariable("amount")); assertEquals("i met my deadline", contextInstance.getVariable("reason")); 3.4 任务分配示例 下一个例子我们将向你展示怎样分配一个任务到用户。因为jBPM工作流引擎与组织模型是独立的,所以任何一种用来计算参与者的表达式语言都是有限制的,因此,你不得不指定一个AssignmentHandler实现,用来包含任务参与者的计算。 public void testTaskAssignment() { // 下面的流程基于hello world 流程。状态节点被一个task-node节点// 所替换。task-node JPDL中的一类节点,它表示一个等待状态并且产生 // 将要完成的任务,这些任务在流程继续之前被执行。 ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( " " " " " + " " " class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler ' />" + "" + " " " + " "" ); // 创建一个流程定义的执行。 ProcessInstance processInstance = new ProcessInstance(processDefinition); Token token = processInstance.getRootToken(); // 让我们起动流程执行,通过默认转换离开开始状态 token.signal(); // signal方法将会把流程阻塞在一个等待状态, // 在这里,就是阻塞在task-node。 assertSame(processDefinition.getNode("t"), token.getNode()); // 当执行到达task-node,一个'change nappy'任务被创建,并且 // NappyAssignmentHandler 被调用,来决定任务将要分配给谁。 // NappyAssignmentHandler 返回'papa'。 // 在一个实际环境中,将使用org.jbpm.db.TaskMgmtSession中的方法// 从数据库获取任务。因为我们不想在这个例子中包含复杂的持久化, // 所以我们仅使用这个流程实例的第一个任务实例(我们知道,在这个 // 测试情景,只有一个任务)。 TaskInstance taskInstance = (TaskInstance) processInstance .getTaskMgmtInstance() .getTaskInstances() .iterator().next(); // 现在我们检查taskInstance 是否真正的分配给了'papa'。 assertEquals("papa", taskInstance.getActorId() ); // 现在我们假设'papa'已经完成了他的职责,并且标示任务为已完成。 taskInstance.end(); // 因为这是要做的最后一个任务(也是唯一一个),所以任务的完成 // 会触发流程实例的继续执行。 assertSame(processDefinition.getNode("end"), token.getNode()); } 3.5 定制动作示例 动作是一种绑定你自己的定制代码到jBPM流程的机制。动作可以与它自己的节点(如果它们与流程的图形化表示是相关的)相关联。动作也可以被放置在事件上,如执行转换、离开节点或者进入节点;如果那样的话,动作则不是图形化表示的一部分,但是在流程执行运行时,当执行触发事件时,它们会被执行。 我们先看一下将要在我们的例子中使用的动作实现:MyActionHandler,这个动作处理实现实际上没有做任何事…仅仅是设置布尔变量isExecuted为true。变量isExecuted是一个静态变量,因此它可以在动作处理的内部访问(即内部方法中),也可以从动作(即在动作类上)验证它的值。 有关动作的更多信息可以在“9.5 动作”中找到。 // MyActionHandler 是一个在jBPM流程执行期间可以执行用户代码的类。 public class MyActionHandler implements ActionHandler { // 在每个测试之前(在setUp方法中), isExecuted 成员被设置为false。 public static boolean isExecuted = false; // 动作将设置isExecuted为true,当动作被执行之后,单元测试会 // 展示。 public void execute(ExecutionContext executionContext) { isExecuted = true; } } 就象前面所提示那样,在每个测试之前,我们将设置静态域 MyActionHandler.isExecuted为false。 // 每个测试都将以设置MyActionHandler的静态成员isExecuted // 为false开始。 public void setUp() { MyActionHandler.isExecuted = false; } 我们将会在转换上开始一个动作。 public void testTransitionAction() { // 下面的流程与hello world 流程不同。我们在从状态“s”到 // 结束状态的转换上增加了一个动作。这个测试的目的就是展示 // 集成java代码到一个jBPM流程是多么的容易。 ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( " " " " " + " " " class='org.jbpm.tutorial.action.MyActionHandler' />" + "" + " " + " "" ); // 让我们为流程定义起动一个新的执行。 ProcessInstance processInstance = new ProcessInstance(processDefinition); // 下面的信号会导致执行离开开始状态,进入状态“s”。 processInstance.signal(); // 这里我们展示MyActionHandler还没有被执行。 assertFalse(MyActionHandler.isExecuted); // ... 并且执行的主路径被定位在状态“s”。 assertSame(processDefinition.getNode("s"), processInstance.getRootToken().getNode()); // 下面的信号将触发根令牌的执行,令牌将会执行带有动作的转换, // 并且在调用signal方法期间动作经会被执行token。 processInstance.signal(); // 我们可以看到MyActionHandler在调用signal方法期间被执行了。 assertTrue(MyActionHandler.isExecuted); } 下一个例子展示了相同的动作,但是现在动作分别被放置在了enter-node和leave-node 事件上。注意,节点与转换相比有更多的事件类型,而转换只有一个,因此动作要放置在节点上应该放入一个event元素中。 ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( " " " " " + " " " class='org.jbpm.tutorial.action.MyActionHandler' />" + "" + " " class='org.jbpm.tutorial.action.MyActionHandler' />" + "" + " " " + " "" ); ProcessInstance processInstance = new ProcessInstance(processDefinition); assertFalse(MyActionHandler.isExecuted); //下面的信号会导致执行离开开始状态,进入状态“s”, // 因此状态's' 被进入,动作被执行。 processInstance.signal(); assertTrue(MyActionHandler.isExecuted); // 我们重新设置MyActionHandler.isExecuted。MyActionHandler.isExecuted = false; // 下一个信号将会触发执行离开状态's',因此动作将被执行。processInstance.signal(); // 请看 assertTrue(MyActionHandler.isExecuted); 第5章部署 jBPM是一个嵌入式BPM引擎,这意味着你可以象安装一个独立的软件产品并集成一样把jBPM嵌入到你自己的java工程中,可以这样做的一个主要方面就是最小化的依赖,本章讨论jbpm库及其依赖。 5.1 Java运行环境 jBPM3要求J2SE1.4.2+ 第6章配置 jBPM配置由java类org.jbpm.JbpmConfiguration来描述,获取JbpmConfiguration 的最简单方式是使用单态实例方法JbpmConfiguration.getInstance()。 如果你想从另外一个源加载配置,你可以使用JbpmConfiguration.parseXxxx方法。static JbpmConfinguration jbpmConfiguration = JbpmConfinguration.getInstance(); JbpmConfiguration是线程安全的,因此可以在一个静态成员中维护,所有的线程都可以把JbpmConfiguration作为一个JbpmContext对象的工厂来使用。JbpmContext表示一个事务,在一个上下文块中JbpmContext使服务可用,上下文块如下: JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { // This is what we call a context block. // Here you can perform workflow operations } finally { jbpmContext.close(); } JbpmContext使一组服务和配置为jBPM可用,这些服务在jbpm.cfg.xml配置文件中被配置,并且使jBPM无论运行在任何java环境中这些服务都可用。 下面是JbpmContext的一个典型配置,就象你在src/config.files/jbpm.cfg.xml中看到的那样: factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' /> factory='org.jbpm.msg.db.DbMessageServiceFactory' /> factory='org.jbpm.scheduler.db.DbSchedulerServiceFactory' /> factory='org.jbpm.logging.db.DbLoggingServiceFactory' /> factory='org.jbpm.security.authentication.DefaultAuthenticationServ iceFactory' /> value='hibernate.cfg.xml' /> value='org/jbpm/calendar/jbpm.business.calendar.properties' /> value='org/jbpm/graph/def/jbpm.default.modules.properties' /> value='org/jbpm/db/hibernate/jbpm.converter.properties' /> value='org/jbpm/graph/action/action.types.xml' /> value='org/jbpm/graph/node/node.types.xml' /> value='org/jbpm/jpdl/par/jbpm.parsers.xml' /> value='org/jbpm/context/exe/jbpm.varmapping.xml' /> /> class='org.jbpm.taskmgmt.impl.DefaultTaskInstanceFactoryImpl' singleton='true' /> class='org.jbpm.jpdl.el.impl.JbpmVariableResolver' singleton='true' /> 在这个配置中你可以看到三部分: l第一部分使用一组服务实现配置jbpm上下文,这些配置的可选项在以后描述特定服务实现的章节中做了描述。 l第二部分是所有配置资源的引用映射,如果你想要定制某些配置文件,这些资源引用可以被修改。 典型情况下,你可以在jbpm-3.x.jar中拷贝一个默认的配置,并且把它放在classpath中的某个位置,然后在这个文件中修改引用为你自己定制版本的配置文件。 l第三部分是在jbpm中使用的一些别名配置,这些配置选项在包含特定主题的章节中做了描述。 缺省配置的一组服务被定位于一个简单的web应用环境和最小的依赖,持久化服务将获得一个jdbc连接,所有其他服务将会使用这个相同的连接来完成它们的服务,因此,工作流的所有操作都被集中到一个JDBC连接的一个事务中,不再需要事务管理器。 JbpmContext包含为大多流程操作所提供的方便方法: public void deployProcessDefinition(ProcessDefinition processDefinition) {...} public List getTaskList() {...} public List getTaskList(String actorId) {...} public List getGroupTaskList(List actorIds) {...} public TaskInstance loadTaskInstance(long taskInstanceId) {...} public TaskInstance loadTaskInstanceForUpdate(long taskInstanceId) {...} public Token loadToken(long tokenId) {...} public Token loadTokenForUpdate(long tokenId) {...} public ProcessInstance loadProcessInstance(long processInstanceId) {...} public ProcessInstance loadProcessInstanceForUpdate(long processInstanceId) {...} public ProcessInstance newProcessInstance(String processDefinitionName) {...} public void save(ProcessInstance processInstance) {...} public void save(Token token) {...} public void save(TaskInstance taskInstance) {...} public void setRollbackOnly() {...} 记住,XxxForUpdate方法将记录所加载的对象为自动保存的,因此不需要再调用save 方法。 指定多个jbpm上下文是可能的,但是你必须确保每个jbpm上下文的name属性必须是唯一的,可以使用JbpmConfiguration.createContext(String name)获取命名的上下文。 service元素定义了一个服务名称和此服务的服务工厂,服务将只会在使用JbpmContext.getServices().getService(String name)请求时被创建。 工厂也可以被作为一个元素来指定,而不是用属性。那样可以用于在工厂对象中注入一些配置信息,负责解析XML的组件创建和装配被调用的对象工厂。 6.1 配置属性 jbpm.byte.block.size:文件附件和二进制变量被存储到数据库,不是作为blob,而是作为一个固定大小的二进制对象列表,这可以方便用于不同数据库并且提高jBPM的全面嵌入能力,这个参数控制了固定长度块的大小。 jbpm.task.instance.factory:定制任务实例的创建方式,在这个属性中指定一个全类名,当你想要定制TaskInstance bean并且向它添加新的属性时,这是有必要的。请参考“11.10 定制任务实例”,指定的类必须实现org.jbpm.tskmgmt.TaskInstanceFactory。 jbpm.variable.resolver:定制jBPM在JSF表达式中寻找第一个术语的方式。 jbpm.msg.wait.timout:定制消息缓存的时间。 6.2 配置文件 下面是对在jBPM中定义的所有配置文件的简短描述。 6.2.1 Hibernate.cfg.xml文件 这个文件包含hibernate配置,并且引用hibernate映射资源文件。 位置:hibernate.cfg.xml文件如果不另外在jbpm.properties文件的 jbpm.hibernate.cfg.xml属性中指定,则jBPM工程中的默认hibernate配置文件在目录src/config.files/hibernate.cfg.xml。 6.2.2 Hibernate查询配置文件 这个文件包含jBPM会话org.jbpm.db.*Session中所使用的hibernate查询。 位置:org/jbpm/db/hibernate.queries.hbm.xml。 6.2.3 节点类型配置文件 这个文件包含了XML节点元素到节点实现类的映射。 位置:org/jbpm/graph/node/node.types.xml。 6.2.4 动作类型配置文件 这个文件包含了XML动作元素到动作实现类的映射。 位置:org/jbpm/graph/action/action.types.xml。 6.2.5 业务日历配置文件 包含了业务时间和空闲时间的定义。 位置:org/jbpm/calendar/jbpm.business.calendar.properties。 6.2.6 变量映射配置文件 指定了流程变量(java对象)的值怎样转换到用于存储到jbpm数据库中的变量实例。 位置:org/jbpm/context/exe/jbpm.varmapping.xml。 6.2.7 转换器配置文件 指定了id到类名的映射。id被存储到数据库, org.jbpm.db.hibernate.ConverterEnumType被用来映射id到单态对象。 位置:org/jbpm/db/hibernate/jbpm.converter.properties。 6.2.8 缺省模块配置文件 指定哪个模块被缺省添加到一个新的流程定义ProcessDefinition。 位置:org/jbpm/graph/def/jbpm.default.modules.properties。 6.2.9 流程档案解析器配置文件 指定流程档案解析的解析器。 位置:org/jbpm/jpdl/par/jbpm.parsers.xml。 6.3 对象工厂 对象工厂可以依照bean的xml配置文件创建对象,配置文件指定了对象将被怎样创建、配置以及组装到一起形成一个完整的对象图。对象工厂可以注入配置和其他bean到一个bean 中。 在最简单的形式中,对象工厂可以从这样一个配置中创建基本类型和java bean: class="org.jbpm.taskmgmt.exe.TaskInstance"/>