如何将BPMN流程部署到Activiti?

  我们通过BPMN可视化工具或者XML配置设置好BPMN流程后,需要部署到流程引擎中执行,Activiti是比较流行的开源BPMN流程引擎,其引起了很多分支,其中著名的是Camunda和Flowable,Camunda是假设真正好的复杂流程肯定需要编码介入,他们是不完全现象BPMN可视化工具能搞定一切,见:不需要编程的任何可视化工具?当然这只是仁者见仁而已。

下面我们以Activiti为例,Activiti从5.5以后到6.0,以及发展到7.0,变化比较大,7.0由于和Spring Cloud结合,从 部署方式和运行方式都有很多不同,Activiti Core和Activiti Cloud Beta1发布!

部署到Activiti涉及到你打算让你的流程引擎以什么方式运行?

1. 将流程引擎作为库包到你的业务系统,好处是流程引擎的事务控制纳入业务控制,缺点是造成流程引擎和业务系统深度耦合,扩展比较难。如果使用Activiti 6的部署包,有activiti-app和activiti-rest两种,如果使用activiti-app部署流程,比如在app中导入流程文件,然后打包成app发布,这是一种流程引擎和任务管理以及表单系统和身份系统放在一起运行的,这种耦合性给Activiti带来商业价值,因为他们的企业版在表单和任务方面提供更强大的功能,如果你觉得四个耦合在一起使用方便,那么可能会购买他们的企业版本,对于Activiti来说,真正cloud化是将这四个系统完全分离,通过Spring Cloud解耦,甚至流程中的事件触发和捕获都通过Spring cloud stream去完成,底层依靠Kafka或rabbitmq,这才是真正可扩展云原生的应用。

2. 将流程引擎作为REST提供方,你的业务系统通过REST调用流程引擎,发布流程,管理流程,完成任务后提交任务,缺点是你需要自己控制事务,使用事务最终一致性,你需要在流程第一步锁定资源,等待流程全部完成后释放锁定资源,以订票系统为例,有订座位和支付两个步骤,先订座位再支付,订座位时锁定位置资源,如果支付失败需要释放座位资源,当然锁定座位需要有timeout,超时后也释放锁定,这个可以通过加入计时边界事件实现。

后者好像需要建模时介入事务,增加复杂性,其实这是事务设计的最好办法,因为事务的英文是transaction,翻译成事务或交易,把事务当成交易去做,特别是长流程,需要一定时间才完成,而且由于人工介入的场景,这是最好的方式,实际中我们很多也是通过业务办法解决的,比如与银行对账,我们是通过将名单变成一个文件,使用ftp上传,我们只要关注是否需要重试,重试几次不成功后人工介入,但是一旦成功,数据肯定全部传过去,这是原子性的,因为数据打包在一个文件中。

在这种REST方式下,我们可以一个流程文件一个REST资源,或者一个REST资源提供多份流程服务,这种粒度划分取决于你的流程使用量了。

这是一个流程一个REST案例:BPMN文件在这里

<process id="simpleProcess" name="Simple Process">
<startEvent id="theStart" />
<sequenceFlow sourceRef="theStart" targetRef="theTask" />

<userTask id="theTask" name="Task" activiti:assignee="${person}">
<documentation>
Do the task.
</documentation>
</userTask>

<sequenceFlow sourceRef="theTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>

这是一个简单的流程,只有一个用户任务,分配给${person}"去做,${person}"是数据变量,Spring Boot的启动程序:


@SpringBootApplication
public class SpringRestActivitiApplication {

public static void main(String[] args) {
SpringApplication.run(SpringRestActivitiApplication.class, args);
}

@Bean
InitializingBean usersAndGroupsInitializer(final IdentityService identityService) {

return new InitializingBean() {
public void afterPropertiesSet() throws Exception {

User admin = identityService.newUser("admin");
admin.setPassword("admin");
identityService.saveUser(admin);

}
};
}
}

加入简单的身份认证admin/admin

通过curl访问:

curl -u admin:admin http://localhost:8080/repository/deployments

或者 postman,设置basic权限。得到结果:

{
"data": [
{
"id": "1",
"name": "SpringAutoDeployment",
"deploymentTime": "2018-09-08T18:04:26.832+08:00",
"category": null,
"url": "http://localhost:8080/repository/deployments/1",
"tenantId": ""
}
],
"total": 1,
"start": 0,
"sort": "id",
"order": "asc",
"size": 1
}

说明已经有一个流程部署其中,就是我们前面XML定义的。

通过下面命令启动流程:

url -u admin:admin -H "Content-Type: application/json" -d '{"processDefinitionKey":"simpleProcess", "variables": [ {"name":"person", "value":"John"}]}' http://localhost:8080/runtime/process-instances

或者postman选择raw,输入JSON参数:

{"processDefinitionKey":"simpleProcess", "variables": [ {"name":"person", "value":"John"}]}

返回结果:

{
"id": "4",
"url": "http://localhost:8080/runtime/process-instances/4",
"businessKey": null,
"suspended": false,
"ended": false,
"processDefinitionId": "simpleProcess:1:3",
"processDefinitionUrl": "http://localhost:8080/repository/process-definitions/simpleProcess:1:3",
"activityId": "theTask",
"variables": [],
"tenantId": "",
"completed": false
}

这个流程启动了,流程id是4。地址在http://localhost:8080/runtime/process-instances/4",

如果想做成一个面向任务的流程REST服务,这个Spring boot案例提供借鉴。

这个案例是Activiti 6 + spring boot 1.5架构,如果想使用Activiti 6 + spring boot 2,不是简单将pom.xml的activiti改为版本2就可以的,activiti 7才默认支持Spring boot2,如果还想使用Activiti 6,这里开源项目提供模板,而且能够集成自己的数据库用户管理系统。

 

工作流与BPM