[size=x-large] 第 4 章 服务[/size]
jBPM和服务相互影响,配置成功之后就可以从流程引擎里获得服务接口。
[size=large]4.1. 流程引擎[/size]
流程引擎是线程安全的,它可以保存在静态变量中,甚至JNDI中或者其他重要位置。在应用中,所有线程和请求都可以使用同一个流程引擎对象,现在就告诉你怎么获得流程引擎。
ProcessEngine processEngine = new Configuration()
.buildProcessEngine();
上面的代码演示了如何通过classpath根目录下默认的配置文件jbpm.cfg.xml创建一个ProcessService。如果你要指定其他位置的配置文件,请使用setResource()方法:
ProcessEngine processEngine = new Configuration()
.setResource("my-own-configuration-file.xml")
.buildProcessEngine();
还有其他setXxxx()方法可以获得配置内容,例如:从InputStream中、从xml字符串中、从InputSource中、从URL中或者从文件(File)中。
我们可以根据流程引擎得到下面的服务:
ProcessService processService = processEngine.getProcessService()
ExecutionService executionService = processEngine.getExecutionService();
ManagementService managementService = processEngine.getManagementService();
TaskService taskService = processEngine.getTaskService();
在配置中定义的这些流程引擎(ProcessEngine)对象,也可以根据类型processEngine.get(Class<T>)或者根据名字processEngine.get(String)来获得。
[size=large]4.2. 部署流程[/size]
ProcessService中包含了所有可以得到流程定义资源的方法。
比如在classpath的资源中的jPDL流程文件order.jpdl.xml,可以使用ProcessService进行部署。如下:
processService.createDeployment()
.addResource("order.jpdl.xml").deploy();
像上面的addResource方法,XML流程定义文件的来源可以是一个文件、url网址、字符串、inputStream、zip或jar压缩包和一个目录。
部署的来源中包含了满足默认命名规范的资源文件,它可能包含各种流程描述和自定义类型。jPDL的部署工具会自动识别后缀名是.jpdl.xml的流程文件。对于那些没有按照规范进行命名的文件,可以使用jpdl提供的方法进行编程设置。
setFileType("my-jpdl-process.someotherextension", "jpdl")
在部署的过程中,流程定义会被分配一个格式为{key}:{version}的id
如果没有提供key,会在名字的基础自动生成。生成的key会替换所有不是字母和数字的字符。
同一个名字关联一个key,反之亦然。
如果没有为流程文件提供版本号,jBPM会自动为它分配一个版本号。请特别注意那些已经部署了的名字相同的流程文件的版本号。它会比已经部署的同一个key的流程定义里最大的版本号还大。没有部署相同key的流程定义的版本号会分配为1,
在下面第1个例子里,我们只提供了流程的名字,没有提供其他信息:
<process nam="Insurance claim">
...
</process>
假设这个流程是第一次部署,下面就是它的属性:
[size=large]表 4.1. 没有key值的属性流程[/size]
Property Value Source
name Insurance claim process xml
key Insurance_claim generated
version 1 generated
id Insurance_claim:1 generated
第2个例子我们将演示如何通过设置流程的key来获得更短的id。
<process name="Insurance claim" key="ICL">
...
</process>
这个流程定义的属性就会像下面这样:
[size=medium]表 4.2. 有key值属性的流程[/size]
Property Value Source
name Insurance claim process xml
key ICL process xml
version 1 generated
id ICL:1 generated
[size=large]4.3. 启动一个新的流程实例[/size]
[size=medium]4.3.1. 最新的流程实例[/size]
下面是为流程定义启动一个新的流程实例的最简单也是最常用的方法:
executionService.startProcessInstanceByKey("ICL");
上面的service的方法会去查找key为ICL的最新版本的流程定义,然后在流程定义里启动流程实例。
当insurance claim流程部署了一个新版本,startProcessInstanceByKey方法会自动去选择最新部署的版本。[size=medium]
4.3.2. 明确流程版本[/size]
换句话说,你如果想根据明确的版本启动流程实例,便可以使用流程定义的id启动流程实例。如下所示:
executionService.startProcessInstanceById("ICL:1");
[size=large]4.3.3. 使用锁[/size]
我们可以为新启动的流程实例分配一个key,key是用户执行的时候定义的。一个流程定义里的所有key必须都是唯一的。在企业的流程里很容易在领域模型里找到唯一的key。例如:序列号或保险编号。
executionService.startProcessInstanceByKey("ICL", "CL92837");
key可以用来创建流程实例的id,格式为{process-key}/{execution-id}。所以上面的代码会创建一个id为ICL/CL92837的流向(execution)。
如果没有提供用户定义的key,数据库就会把主键作为key。这样可以使用如下方式获得id:
Execution execution = executionService.startProcessInstanceByKey("ICL");
String executionId = execution.getId();
我们推荐使用用户定义的key,特别是在你的应用代码里,你可以得到有效的key。根据用户定义的key,你可以直接使用流向的id,而不用根据流程的变量进行查询。
[size=large]4.3.4. 使用变量[/size]
当一个新的流程实例启动时就会提供一组对象参数。将这些参数放在variables变量里,然后可以在流程实例创建和启动时使用。
Map<String,Object> varialbes = new HashMap<String,Object>();
variables.put("customer","John Doe");
variables.put("type","Accident");
variables.put("amoutn","new Float(763.74)");
executionService.startProcessInstanceByKey("ICL",variables);
[size=large]4.4. 执行等待的流向(execution)[/size]
流程处理定义中必须执行一些活动(activity)。流程处理的任何一个活动(activity)都可能是被流程系统执行或者被外部参与者执行。当一个活动(activity)是被外部参与者执行时,流向必须等待外部参与者通知流程系统活动(activity)已经完成。因此流向要么是在执行,要么实在等待外部参与者。你会发现大部分的流程的都在等待外部参与者,因为人的动作都是很慢的。:)两个等待状态之间,被流程系统消耗的时间通常都是很短的。
状态(state)是一种基本活动(activity),它告知外部参与者有哪些事情必须执行,流向会一直等待到signal(外部强制执行)。
当流向处在等待状态时,可以被外部触发器通过signal方法强制执行。我们建议你使用流程定义和流向key来获得一个流向(execution)。在下面的代码中,ICL流程定义的82436流向key被使用了。
executionService.signalExecutionByKey("ICL","82436");
我们还可以这样使用,这个必须执行signal的流向可以通过一个唯一的id被引用,下面的代码中指定了executionId为ICL/82436流向:
executionSerivice.signalExecutionById("ICL/82436");
一些数据可以通过signal传递给系统:信号名和参数。信号名会根据流向(execution)的当前活动(activity)被使用。参数存储在流程的变量里。
Map<String,Object> parameters = new HashMap<String,Object>();
parameters.put("quality","a+");
parameters.put("target","profit");
executionService.signalExecutionById("ICL/82436","Accept",parameters);
[size=large]
4.5. 任务服务[/size]
[size=large]4.6. 管理服务[/size]
jBPM和服务相互影响,配置成功之后就可以从流程引擎里获得服务接口。
[size=large]4.1. 流程引擎[/size]
流程引擎是线程安全的,它可以保存在静态变量中,甚至JNDI中或者其他重要位置。在应用中,所有线程和请求都可以使用同一个流程引擎对象,现在就告诉你怎么获得流程引擎。
ProcessEngine processEngine = new Configuration()
.buildProcessEngine();
上面的代码演示了如何通过classpath根目录下默认的配置文件jbpm.cfg.xml创建一个ProcessService。如果你要指定其他位置的配置文件,请使用setResource()方法:
ProcessEngine processEngine = new Configuration()
.setResource("my-own-configuration-file.xml")
.buildProcessEngine();
还有其他setXxxx()方法可以获得配置内容,例如:从InputStream中、从xml字符串中、从InputSource中、从URL中或者从文件(File)中。
我们可以根据流程引擎得到下面的服务:
ProcessService processService = processEngine.getProcessService()
ExecutionService executionService = processEngine.getExecutionService();
ManagementService managementService = processEngine.getManagementService();
TaskService taskService = processEngine.getTaskService();
在配置中定义的这些流程引擎(ProcessEngine)对象,也可以根据类型processEngine.get(Class<T>)或者根据名字processEngine.get(String)来获得。
[size=large]4.2. 部署流程[/size]
ProcessService中包含了所有可以得到流程定义资源的方法。
比如在classpath的资源中的jPDL流程文件order.jpdl.xml,可以使用ProcessService进行部署。如下:
processService.createDeployment()
.addResource("order.jpdl.xml").deploy();
像上面的addResource方法,XML流程定义文件的来源可以是一个文件、url网址、字符串、inputStream、zip或jar压缩包和一个目录。
部署的来源中包含了满足默认命名规范的资源文件,它可能包含各种流程描述和自定义类型。jPDL的部署工具会自动识别后缀名是.jpdl.xml的流程文件。对于那些没有按照规范进行命名的文件,可以使用jpdl提供的方法进行编程设置。
setFileType("my-jpdl-process.someotherextension", "jpdl")
在部署的过程中,流程定义会被分配一个格式为{key}:{version}的id
如果没有提供key,会在名字的基础自动生成。生成的key会替换所有不是字母和数字的字符。
同一个名字关联一个key,反之亦然。
如果没有为流程文件提供版本号,jBPM会自动为它分配一个版本号。请特别注意那些已经部署了的名字相同的流程文件的版本号。它会比已经部署的同一个key的流程定义里最大的版本号还大。没有部署相同key的流程定义的版本号会分配为1,
在下面第1个例子里,我们只提供了流程的名字,没有提供其他信息:
<process nam="Insurance claim">
...
</process>
假设这个流程是第一次部署,下面就是它的属性:
[size=large]表 4.1. 没有key值的属性流程[/size]
Property Value Source
name Insurance claim process xml
key Insurance_claim generated
version 1 generated
id Insurance_claim:1 generated
第2个例子我们将演示如何通过设置流程的key来获得更短的id。
<process name="Insurance claim" key="ICL">
...
</process>
这个流程定义的属性就会像下面这样:
[size=medium]表 4.2. 有key值属性的流程[/size]
Property Value Source
name Insurance claim process xml
key ICL process xml
version 1 generated
id ICL:1 generated
[size=large]4.3. 启动一个新的流程实例[/size]
[size=medium]4.3.1. 最新的流程实例[/size]
下面是为流程定义启动一个新的流程实例的最简单也是最常用的方法:
executionService.startProcessInstanceByKey("ICL");
上面的service的方法会去查找key为ICL的最新版本的流程定义,然后在流程定义里启动流程实例。
当insurance claim流程部署了一个新版本,startProcessInstanceByKey方法会自动去选择最新部署的版本。[size=medium]
4.3.2. 明确流程版本[/size]
换句话说,你如果想根据明确的版本启动流程实例,便可以使用流程定义的id启动流程实例。如下所示:
executionService.startProcessInstanceById("ICL:1");
[size=large]4.3.3. 使用锁[/size]
我们可以为新启动的流程实例分配一个key,key是用户执行的时候定义的。一个流程定义里的所有key必须都是唯一的。在企业的流程里很容易在领域模型里找到唯一的key。例如:序列号或保险编号。
executionService.startProcessInstanceByKey("ICL", "CL92837");
key可以用来创建流程实例的id,格式为{process-key}/{execution-id}。所以上面的代码会创建一个id为ICL/CL92837的流向(execution)。
如果没有提供用户定义的key,数据库就会把主键作为key。这样可以使用如下方式获得id:
Execution execution = executionService.startProcessInstanceByKey("ICL");
String executionId = execution.getId();
我们推荐使用用户定义的key,特别是在你的应用代码里,你可以得到有效的key。根据用户定义的key,你可以直接使用流向的id,而不用根据流程的变量进行查询。
[size=large]4.3.4. 使用变量[/size]
当一个新的流程实例启动时就会提供一组对象参数。将这些参数放在variables变量里,然后可以在流程实例创建和启动时使用。
Map<String,Object> varialbes = new HashMap<String,Object>();
variables.put("customer","John Doe");
variables.put("type","Accident");
variables.put("amoutn","new Float(763.74)");
executionService.startProcessInstanceByKey("ICL",variables);
[size=large]4.4. 执行等待的流向(execution)[/size]
流程处理定义中必须执行一些活动(activity)。流程处理的任何一个活动(activity)都可能是被流程系统执行或者被外部参与者执行。当一个活动(activity)是被外部参与者执行时,流向必须等待外部参与者通知流程系统活动(activity)已经完成。因此流向要么是在执行,要么实在等待外部参与者。你会发现大部分的流程的都在等待外部参与者,因为人的动作都是很慢的。:)两个等待状态之间,被流程系统消耗的时间通常都是很短的。
状态(state)是一种基本活动(activity),它告知外部参与者有哪些事情必须执行,流向会一直等待到signal(外部强制执行)。
当流向处在等待状态时,可以被外部触发器通过signal方法强制执行。我们建议你使用流程定义和流向key来获得一个流向(execution)。在下面的代码中,ICL流程定义的82436流向key被使用了。
executionService.signalExecutionByKey("ICL","82436");
我们还可以这样使用,这个必须执行signal的流向可以通过一个唯一的id被引用,下面的代码中指定了executionId为ICL/82436流向:
executionSerivice.signalExecutionById("ICL/82436");
一些数据可以通过signal传递给系统:信号名和参数。信号名会根据流向(execution)的当前活动(activity)被使用。参数存储在流程的变量里。
Map<String,Object> parameters = new HashMap<String,Object>();
parameters.put("quality","a+");
parameters.put("target","profit");
executionService.signalExecutionById("ICL/82436","Accept",parameters);
[size=large]
4.5. 任务服务[/size]
[size=large]4.6. 管理服务[/size]