一、 JBPM4的结构特点
1.嵌入式的工作流引擎,不需要依赖特定的中间件或服务器,减少了硬件和软件的绑定,完全支持嵌入式应用的
业务流程开发框架,可以在事务处理、数据持久化等各个方面与业务应用程序进行灵活的集成。
2.可拔插的体系架构,采用模块化的架构设计,采用了IOC的设计理念,各模块之间可以比较方便地解除耦合或
替换不同的实现,例如持久化、事务处理、身份认证、日志服务等,都由可选模块实现。
3. 易扩展的流程语言。
二、 Jbpm4的安装配置
1.下载地址:http://sourceforge.net/projects/jbpm/
2.解压资源包,进入目录install,在控制台下运行脚本:ant demo.setup.tomcat。会执行如下操作:
1)下载安装Tomcat.
2)安装HSQLDB,并创建数据表结构。
3)启动Tomcat,创建examples.bar业务流程归档,并发布到JBPM数据库中,初始化相关用户和组。
4)下载安装Eclipse,并启动Eclipse.
5)安装JBPM Web控制台。
6)安装Signavio Web 设计器。
3.在Eclipse中安装GPD插件,利用eclipse的软件升级指定GPD安装文件,文件为
下载资源包中install/src/gpd/jbpm-gpd-site.zip。
4.添加jbdl4 Schema检验,在eclipse中配置schema,指定jbpm4安装目录下src文件夹中jpdl.xsd文件。
步骤为:Window->Preferences->XML->XML CataLog->Add->File System。
三、 Jbpm流程API
1.流程相关概念
流程定义:对业务过程步骤的描述,表现为若干"活动"节点通过"转移"线条串联。
流程实例:表示流程定义在运行时特有的执行例程。
流程执行:流程实例在其生命周期中,指向当前执行活动的指针。
2.流程的6个Service API,可通过流程引擎对象的接口方法获取。
ProcessEngine processEngine = Configuration.getProcessEngine();
1)RepositoryService,流程资源服务的接口。提供对流程定义的部署、查询、删除等操作。
2)ExecutionService,流程执行服务的接口。提供启动流程实例、“执行”推进、设置流程变量等操作。
3)TaskService,人工任务服务的接口。提供对任务的创建、提交、查询、保存、删除等操作。
4)HistoryService,流程历史服务的接口。提供对流程历史库中历史流程实例、历史活动实例等记录的查询操作。
5)IdentityService,身份认证服务的接口。提供对流程用户、用户组以及组成员关系的相关服务。
6)ManagementService,流程管理控制服务的接口。提供异步工作(Job)相关的执行和查询操作。
3.流程的布署和删除
1)流程的布署
String deploymentId = repositoryService.createDeployment() .addResourceFromClasspath("org/jbpm/examples/task/assignee/process.jpdl.xml") .deploy(); // 可多次调用addResourceFromClasspath方法部署其它流程定义
2)流程的删除
repositoryService.deleteDeploymentCascade(deploymentId);
4.发起流程实例
1)流程Key
ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL");
2)流程Id
ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL-1");
3)根据业务键指定流程实例ID
ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL",“Order09278”);
4)传入流程变量
ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL", variablesMap);
5.唤醒等待状态的执行
executionService.signalExecutionById(executionId);
6.获得用户的任务列表
List<Task> taskList = taskService.findPersonalTasks("johndoe");
7.任务的完成提交
1)将用户界面的任务表单内容存入任务
taskService.setVariables(taskId,variablesMap);
2)根据任务ID完成任务
taskService.completeTask(taskId);
3)根据任务ID完成任务,同时设入变量
taskService.completeTask(taskId, variablesMap);
4)根据任务ID完成任务,并指定下一步的转移路径
taskService.completeTask(taskId, outcome);
8.流程历史实例获取
1)获得流程定义的所有历史流程实例,返回结果按开始时间排序
List<HistoryProcessInstance> historyProcessInstances = historyService .createHistoryProcessInstanceQuery() .processDefinitionId("ICL-1") .orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME).list();
2)获得流程的历史活动实例,可指定具体名称的活动实例
List<HistoryActivityInstance> historyActivityInstances = historyService .createHistoryActivityInstanceQuery().processDefinitionId("ICL-1").list();
9.查询结果分页
1)流程实例查询分页
List<ProcessInstance> results = executionService.createProcessInstanceQuery() .processDefinitionId("ICL-1").page(0, 50).list();
2)流程任务查询的分页
List<Task> myTasks = taskService.createTaskQuery() .processInstanceId("ICL.Order09278") .assignee("Alex") .page(10, 20).list();
四、 流程定义
1.流程控制活动
1)start,开始活动
2)state,状态活动
3)decision,判断活动
4)fork,分支活动
5)join,聚合活动
6)end,结束活动
2.State活动
Jpdl定义:
<state name="wait for response"> <transition name="accept" to="submit document" /> <transition name="reject" to="try again"/> </state> <state name="submit document"/> <state name="try again"/>
// 获取流程实例ID
String executionId = processInstance.findActiveExecutionIn("wait for response").getId(); // 触发accept流向 processInstance = executionService.signalExecutionById(executionId, "accept");
3.decision活动
1)使用condition元素判断decision活动
Jpdl:
<!-- decision 中会运行并判断每一个transition 里的判断条件。 当遇到一个嵌套条件是true 或者没有设置判断条件的转移, 那么转移就会被运行 --> <decision name="evaluate document" > <transition to="submit document" > <condition expr="#{content==’good’}" /> </transition> <transition to="try again"> <condition expr="#{content==’bad’}" /> </transition> <transition to="give up"/> </decision> <state name="submit document"/> <state name="try again"/> <state name="give up"/>
Map<String, Object> variables = new HashMap<String, Object>(); variables.put("content", "good"); // 由于传入变量为good,流向了submit document活动 ProcessInstance processInstance = executionService .startProcessInstanceByKey("DecisionConditions", variables);
2)使用decision的expr属性判断decision活动。
<!--可选择的状态结点,expr指定将被运行的指定脚本 --> <decision name="evaluate document" expr="#{content}" > <transition name="good" to="submit document"/> <transition name="bad" to="try again"/> <transition name="ugly" to="give up"/> </decision>
流程执行操作同上面condition元素的操作。
3)使用decision活动的handler元素判断decision活动。
<!-- decision handler决定处理器继承了DecisionHandler 接口的java 类, 决定处理器负责选择向外转移 --> <decision name="evaluate document" g="96,102,48,48"> <handler class="org.jbpm.examples.decision.handler.ContentEvaluation"/> <transition name="good" to="submit document"/> <transition name="bad" to="try again"/> <transition name="ugly" to="give up"/> </decision>
ContentEvaluation类如下:
public class ContentEvaluation implements DecisionHandler { public String decide(OpenExecution execution) { String content = (String) execution.getVariable("content"); return content; } }
流程执行操作同上面condition元素的操作。
Decision活动和state活动都可以实现条件流转,但二者的主要区别如下:
如果decision活动定义的流转条件没有任何一个得到满足,那么流程实例将无法进行下去,抛出异常。
而state活动在没有条件满足的条件下将流向state活动定义的第一条流出转移,从而往下流转。
因此decision活动具有更加严格的条件判断特性。
4.fork-join活动
Jpdl:
<!-- fork活动在此产生3个并行分支,这些流程分支可以同步执行。 --> <fork name="fork"> <transition to="send invoice"/> <transition to="load truck"/> <transition to="print shipping documents"/> </fork> <state name="send invoice"> <transition to="final join"/> </state> <state name="load truck"> <transition to="shipping join"/> </state> <state name="print shipping documents"> <transition g="378,213:" to="shipping join"/> </state> <!--join活动为流程的合并,load truck和print shipping documents在此聚合 --> <join name="shipping join"> <transition to="drive truck to destination"/> </join> <state name="drive truck to destination"> <transition to="final join"/> </state> <!-- drive truck to destination活动和send invoice活动在此完成最终的聚合 --> <join name="final join"> <transition to="end"/> </join>
Fork活动可以使流程在一条主干上出现并行的分支,join活动则可以使流程的并行分支聚合成一条主干。
部分执行测试代码如下:
ProcessInstance processInstance = executionService .startProcessInstanceByKey("ConcurrencyGraphBased"); // 当前活动为产生的3个分支活动 assertNotNull(processInstance.findActiveExecutionIn("send invoice")); assertNotNull(processInstance.findActiveExecutionIn("load truck")); assertNotNull(processInstance.findActiveExecutionIn("print shipping documents")); // 执行send invoice活动,流程会在聚合活动上等待其它分支的到来 String sendInvoiceExecutionId = processInstance .findActiveExecutionIn("send invoice").getId(); processInstance = executionService.signalExecutionById(sendInvoiceExecutionId);