BPMN 2.0介绍
- 业务流程模型注解(BusinessProcess Modeling Notation - BPMN)是业务流程模型的一种规范图形注解.这个规范是由对象治理组(Object Management Group - OMG)保护的
- BPMN标准的2.0版本容许增加准确的技术细节在BPMN的图形和元素中,同时制订BPMN元素的执行语法.通过应用XML语言来指定业务流程的可执行语法,BPMN标准曾经演变为业务流程的语言,能够执行在任何兼容BPMN2的流程引擎中,同时仍然能够应用弱小的图形注解
简略来说,BPMN即图标与标签的联合
定义一个流程
- 创立一个新的XML文件并命名,确认文件后缀为 .bpmn20.xml或 .bpmn, 否则引擎无奈公布
- BPMN 2.0根节点是definitions节点. 这个元素中,能够定义多个流程定义(不过倡议每个文件只蕴含一个流程定义, 能够简化开发过程中的保护难度)
一个空的流程定义如下所示:留神definitions元素起码也要蕴含xmlns和 targetNamespace的申明
targetNamespace能够是任意值,它用来对流程实例进行分类
<definitionsxmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"xmlns:activiti="http://activiti.org/bpmn"targetNamespace="Examples"><process id="myProcess" name="My First Process">..</process></definitions>
能够抉择增加线上的BPMN 2.0格局地位:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd
- ==process元素有两个属性:==
id: 这个属性是必须的,对应着Activiti ProcessDefinition对象的key属性.id能够用来启动流程定义的流程实例,通过RuntimeService的startProcessInstanceByKey办法
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
==留神:== 它和startProcessInstanceById办法不同:这个办法冀望应用Activiti引擎在公布时主动生成的id.能够通过调用processDefinition.getId() 办法取得这个值,生成的id的格局为 key:version, 最大长度限度为64个字符, 如果在启动时抛出了一个ActivitiException: 阐明生成的id太长了,须要限度流程的key的长度
name: 这个属性是可选的, 对应ProcessDefinition的name属性.引擎本人不会应用这个属性,是用来在用户接口显示便于浏览的名称
BPMN流程示例前提
- 曾经装置Activiti并且可能运行Activiti Demo
- 应用了独立运行的H2服务器
批改db.properties,设置其中的jdbc.url=jdbc:h2:tcp://localhost/activiti,而后启动独立服务器
指标
- 学习Activiti和一些根本的BPMN 2.0概念
- 最终后果是一个简略的Java SE程序能够公布流程定义,通过Activiti引擎API操作流程
应用一些Activiti相干的工具,构建本人的业务流程web利用
用例
- 每个月都要给公司领导一个金融报表,由会计部门负责
当报表实现时,一个上级领导须要审批文档,而后能力发给所有领导
流程图
流程的图形化BPMN 2.0标记:
空开始事件(左侧圆圈),前面是两个用户工作:制作月度财报和验证月度财报,最初是空完结事件(右侧粗线圆圈)XML内容
在业务流程的XML中很容易找到流程的次要元素:
- (空)开始事件是流程的入口
用户工作是流程中与操作者相干的工作申明:
- 第一个任务分配给accountancy组
- 第二个任务分配给management组
- 当流程达到空完结事件就会完结
这些元素都应用连线连贯,这些连线领有source和target属性,定义了连线的方向
<definitions id="definitions"targetNamespace="http://activiti.org/bpmn20"xmlns:activiti="http://activiti.org/bpmn"xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"> <process id="financialReport" name="Monthly financial report reminder process"> <startEvent id="theStart" /> <sequenceFlow id='flow1' sourceRef='theStart' targetRef='writeReportTask' /> <userTask id="writeReportTask" name="Write monthly financial report" > <documentation> Write monthly financial report for publication to shareholders. </documentation> <potentialOwner> <resourceAssignmentExpression> <formalExpression>accountancy</formalExpression> </resourceAssignmentExpression> </potentialOwner> </userTask> <sequenceFlow id='flow2' sourceRef='writeReportTask' targetRef='verifyReportTask' /> <userTask id="verifyReportTask" name="Verify monthly financial report" > <documentation> Verify monthly financial report composed by the accountancy department. This financial report is going to be sent to all the company shareholders. </documentation> <potentialOwner> <resourceAssignmentExpression> <formalExpression>management</formalExpression> </resourceAssignmentExpression> </potentialOwner> </userTask> <sequenceFlow id='flow3' sourceRef='verifyReportTask' targetRef='theEnd' /> <endEvent id="theEnd" /> </process></definitions>
启动一个流程实例
- 创立好业务流程的流程定义,就能够创立流程实例
- 一个流程实例对应了特定月度财报的创立和审批,所有流程实例都共享同一个流程定义
为了应用流程定义创立流程实例,首先要公布业务流程:
- 流程定义会保留到长久化的数据存储里,是为Activiti引擎特地配置的.所以部署好业务流程,在引擎重启后还能找到流程定义
- BPMN 2.0流程文件会解析成内存对象模型, 能够通过Activiti API操作
通过上面的API公布流程,所有与Activiti引擎的交互都是通过services
Deployment deployment = repositoryService.createDeployment().addClasspathResource("FinancialReportProcess.bpmn20.xml").deploy();
启动一个新流程实例,应用咱们定义在流程定义里的id(对应XML文件中的process元素).==留神这里的id对于Activiti来说,应该叫做key==,个别在流程模型中应用的ID,在Activiti中都是Key:比方工作ID
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("financialReport");
这样创立一个流程实例:
- 首先进入开始事件
- 开始事件之后,它会沿着所有的外出连线执行,达到第一个工作(“制作月度财报”)
- Activiti会把一个工作保留到数据库里.这时,调配到这个工作的用户或群组会被解析,也会保留到数据库里
- 须要留神,Activiti引擎会继续执行流程的环节,除非遇到一个 期待状态:比方用户工作
- 在期待状态下,以后的流程实例的状态会保留到数据库中.直到用户决定实现工作能力扭转这个状态
- 这时,引擎会继续执行,直到遇到下一个期待状态,或流程完结
- 如果两头引擎重启或解体,流程状态也会平安的保留在数据库里
- 工作创立之后,startProcessInstanceByKey会在达到用户工作这个期待状态之后才会返回.这时,任务分配给了一个组,这意味着这个组是执行这个工作的候选组
当初将所有货色都放在一起,来创立一个简略的java程序:
- 创立一个Java我的项目,把Activiti的jar和依赖放到classpath下:这些都能够在Activiti公布包的libs目录下找到
- 在调用Activiti服务之前,咱们必须结构一个ProcessEngine,能够让咱们拜访服务
这里咱们应用[独自运行]的配置,这会应用demo装置时的数据库来构建ProcessEngine
public static void main(String[] args) {// Create Activiti process engineProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration().buildProcessEngine();// Get Activiti servicesRepositoryService repositoryService = processEngine.getRepositoryService();RuntimeService runtimeService = processEngine.getRuntimeService();// Deploy the process definitionrepositoryService.createDeployment().addClasspathResource("FinancialReportProcess.bpmn20.xml").deploy();// Start a process instanceruntimeService.startProcessInstanceByKey("financialReport");}
工作列表
能够通过TaskService来取得工作,增加以下逻辑:
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list();
留神传入的用户必须是accountancy组的一个成员,要和流程定义中绝对应:
<potentialOwner><resourceAssignmentExpression> <formalExpression>accountancy</formalExpression></resourceAssignmentExpression></potentialOwner>
也能够应用群组名称,通过工作查问API来取得相干的后果.在代码中增加如下逻辑:
TaskService taskService = processEngine.getTaskService();List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
因为配置的ProcessEngine应用了与demo雷同的数据,能够登录到Activiti Explorer.默认,accountancy(会计)组里没有任何人:
- 登录
- 点击组
- 创立一个新组
- 点击用户
- 把组分配给fozzie
- 应用fozzie/fozzie登录
- 就能够启动咱们的业务流程了,抉择Processes页,在[月度财报]的[操作]列点击[启动流程]
流程会执行到第一个用户工作.因为咱们以kermit登录,在启动流程实例之后,就能够看到有了一个新的待领工作.抉择工作页来查看这条新工作.留神即便流程被其他人启动,工作还是会被会计组里的所有人作为一个候选工作看到
支付工作
- 当初一个会计要认领这个工作
认领当前,这个用户就会成为工作的执行人,工作会从会计组的其余成员的工作列表中隐没.认领工作的代码:
taskService.claim(task.getId(), "fozzie");
工作会进入认领工作人的集体工作列表:
List<Task> tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
在Activiti Explorer UI中,点击认领按钮,会执行雷同的操作.工作会挪动到登录用户的集体工作列表.你也会看到工作的执行人曾经变成以后登陆的用户:
实现工作
- 当初会计能够开始进行财报的工作
报告实现后,他能够实现工作,意味着工作所需的所有工作都实现
taskService.complete(task.getId());
对于Activiti引擎:
- 须要一个内部信息来让流程实例继续执行
- 工作会把本人从运行库中删除
- 流程会沿着独自一个外出连线执行,挪动到第二个工作(审批报告)
- 与第一个工作雷同的机制会应用到第二个工作上,不同的是工作是调配给management组
在demo中:
- 实现工作是通过点击工作列表中的实现按钮
- 因为Fozzie不是会计,咱们先从Activiti Explorer登记
而后应用kermit登陆(经理),第二个工作会进入未分配任务列表
完结流程
- 审批工作像之前一样查问和支付.
- 实现第二个工作会让流程执行到完结事件,就会完结流程实例
- 流程实例和所有相干的运行数据都会从数据库中删除
- 登录Activiti Explorer就能够进行验证,能够看到保留流程运行数据的表中曾经没有数据:
能够应用historyService判断流程是否曾经完结:
HistoryService historyService = processEngine.getHistoryService();HistoricProcessInstance historicProcessInstance =historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());
源码
思考到你可能会在Activiti Explorer UI中启动一些流程实例,这样,它会取得多个工作,而不是一个,所以代码能够始终失常运行:
public class TenMinuteTutorial {public static void main(String[] args) { // Create Activiti process engine ProcessEngine processEngine = ProcessEngineConfiguration .createStandaloneProcessEngineConfiguration() .buildProcessEngine(); // Get Activiti services RepositoryService repositoryService = processEngine.getRepositoryService(); RuntimeService runtimeService = processEngine.getRuntimeService(); // Deploy the process definition repositoryService.createDeployment() .addClasspathResource("FinancialReportProcess.bpmn20.xml") .deploy(); // Start a process instance String procId = runtimeService.startProcessInstanceByKey("financialReport").getId(); // Get the first task TaskService taskService = processEngine.getTaskService(); List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list(); for (Task task : tasks) { System.out.println("Following task is available for accountancy group: " + task.getName()); // claim it taskService.claim(task.getId(), "fozzie"); } // Verify Fozzie can now retrieve the task tasks = taskService.createTaskQuery().taskAssignee("fozzie").list(); for (Task task : tasks) { System.out.println("Task for fozzie: " + task.getName()); // Complete the task taskService.complete(task.getId()); } System.out.println("Number of tasks for fozzie: " + taskService.createTaskQuery().taskAssignee("fozzie").count()); // Retrieve and claim the second task tasks = taskService.createTaskQuery().taskCandidateGroup("management").list(); for (Task task : tasks) { System.out.println("Following task is available for accountancy group: " + task.getName()); taskService.claim(task.getId(), "kermit"); } // Completing the second task ends the process for (Task task : tasks) { taskService.complete(task.getId()); } // verify that the process is actually finished HistoryService historyService = processEngine.getHistoryService(); HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult(); System.out.println("Process instance end time: " + historicProcessInstance.getEndTime());}}
总结
能够通过Activiti中的BPMN 2.0构造,对业务流程进行以下方面的:
- 定义网关来实现决策环节: 经理能够驳回财报,从新给会计创立一个工作
- 思考应用变量: 能够保留或援用报告,把它显示到表单中
- 在流程最初退出服务工作: 把报告发给每个领导