一、主流流程引擎对比(不讨论JFlow)
框架 | Flowable | JBPM | Activiti | Camunda | OSWorkflow | CompileFlow |
---|---|---|---|---|---|---|
来源 | 国外 | 国外 | 国外 | 国外 | 国外 | 国内 |
是否收费 | 社区版开源 | 开源 | 开源 | 社区版开源 | 开源 | 开源 |
社区活跃度 | 较活跃 | 较活跃 | 活跃 | 不活跃 | 不活跃 | 不活跃 |
建模工具内容 | BPMN2/CMMN/DMN | BPMN2 | BPMN2 | BPMN2/CMMN/DMN | BPMN2 | 淘宝BPM |
持久层引擎 | JPA | JPA | MyBatis | MyBatis | MyBatis | MyBatis |
扩展节点(Mule\Http等) | √ | × | × | √ | × | × |
SpringBoot | √ | √ | √ | √ | √ | √ |
SpringCloud | × | × | √ | × | × | × |
Rest接口 | √ | √ | √ | √ | √ | √ |
功能 | 多 | 少 | 少 | 多 | 少 | 少 |
级别 | 重量级 | 轻量级 | 轻量级 | 轻量级 | 轻量级 | 轻量级 |
生成表数 | 47张 | 18张 | 25张 | 19张 | 9张 | 10张 |
性能 | 优 | 中 | 中 | 优 | 优 | 优 |
稳定性 | 优 | 中 | 中 | 优 | 优 | ? |
外部任务 | 支持的不好 | 不支持 | 不支持 | 支持 | 不支持 | 不支持 |
缺点 | 开源版维护不及时、部分功能闭源、仅支持从开始节点运转实例 | 接口不友好,整个架构体系很乱 | 维护不及时、功能缺少 | 对SpringCloud支持不好,需要自己实现分布式,文档少遇到问题可能需要直接找作者 | 不支持会签、跳转、退回、加签等操作,需要自己扩展开发 | 阿里2020年刚开源,用户少,稳定性有待考证,与OSWorkflow功能类似 |
优点 | 功能完善,性能稳定性都好 | 无 | 社区用户多,遇到问题容易找到解决方案,支持SpringCloud | 功能完善,架构轻量,性能稳定性都好 | 架构轻量 | 无 |
二、BPMN概念
- 任务(Task)
- 发送任务(send task):用来向外部Participant发送消息的任务,一旦消息发送出去,该任务就完成了
- 接收任务(receive task):用来等待外部Participant消息的任务,一旦接收到外部消息该任务就标记为完成状态,很多时候,一个流程都会以一个Receive Task作为开始,通过接收一条外部消息来启动流程
- 用户任务(user task):需要人工完成的任务,需要指定执行的用户或角色,并提供相应的输入(表单),才能继续执行
- 手动任务(manual task):需要人工完成的任务,此任务是否完成不影响流程引擎的继续执行
- 业务规则任务(business rule task):被用作同步执行一个或者多个规则,一般引用DMN决策模型标记。
- 服务任务(service task):通过Web服务来自动完成的任务
- 脚本任务(script task):通过引擎可识别的脚本语言来进行自动化操作,如Groovy脚本
- 参与者(Participant)
- 泳道(Lane):由相同的责任人负责执行的任务放在一起构成一个泳道
- 泳池(Pool):一个完整的工作流程需要由多个责任人负责执行的任务组合在一起协作完成,每个责任人的任务放在一起形成一个泳道,而这些泳道组合在一起就构成了泳池。
- 泳道图(Swimlane Diagram):也叫跨职能流程图,旨在分析和展示各个部门在同一任务流程上的不同进程,明确流程环节所属的阶段、流程环节负责人、组织机构或部门。泳道图的名称由来,是流程图中对职能部门的划分像游泳池泳道相类似比拟而来。
- 子流程(Subprocess)
- 嵌套子流程(Embedded Subprocess):子流程是包含其他活动、网关、事件等的活动,其本身形成的流程是更大流程的一部分。子流程完全在父流程中定义,由父流程调用
- 事件子流程(Event Subprocess):只有事件触发的子流程才能由此活动调起
- 门路(Gateway)
- 排它门路(Exclusive (XOR)):用于多选一的场景。从它分出的路径上可以设置判断条件
- 并行门路(Parallel (AND)): 用于多条路径共同执行的场景。从它分出的路径上不可设置判断条件
- 包含门路(Inclusive (OR)):用于执行部分路径的场景(判断成功的路径)。从它分出的路径上可设置判断条件
- 事件门路(Event-based):用于由事件触发执行路径的场景。发出的路径上不设置判断条件
- 事件(Event)
- 开始事件(Start Event):必须定义的流程开始节点
- 结束事件(End Event):必须定义的流程结束节点
- 中间事件(Intermediate Event):这个事件虽然没有具体的触发器,但定义为抛出事件
- 消息事件(Message Event):消息事件可以出现在流程的任何位置,与消息任务不同点在于消息任务还可以挂载其它边界事件
- 定时事件(Timer Event):定时事件可用作开始事件、中间事件、边界事件,同时作为边界事件支持中断和非中断
- 信号事件(Signal Event):信号事件是全局范围的,它通过广播的形式通知所有关注此事件的流程
- 条件事件(Conditional Event):条件事件是一种等待事件,只有当变量满足条件时才会触发
-
会签
指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,需全部同意之后,审批才可到下一审批节点。 -
或签
指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,只要其中任意一人审批即可到下一审批节点。 -
表单(form)
表单可以嵌入到用户任务中,后续可以在审批中填入相应数据以流转到相应节点
外置表单:可以自己创建表单生成HTML文件,然后让用户任务引用
内置表单:Camunda自己提供 数字、日期、文本、多选、下拉、单选、图片、iFrame、按钮等。。。并可以转换为JSON格式数据
三、项目实战
1. SpringBoot集成
1)引入Jar包,JDK8建议用7.17,再高版可能不支持了
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter</artifactId>
<version>7.17.0</version>
</dependency>
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
<version>7.17.0</version>
</dependency>
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
<version>7.17.0</version>
</dependency>
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter-external-task-client</artifactId>
<version>7.17.0</version>
</dependency>
2)配置yml
3)生成表结构
ACT_ID_:表示用户模块,配置文件里面的用户信息就在此模块
ACT_HI_:表示流程历史记录
ACT_RE_:表示流程资源存储
ACT_RU_:表示流程运行时数据,流程结束后会删除
ACT_GE_*:流程通用数据
2. JAVA API
class | 作用 |
---|---|
RepositoryService | 操作流程定义 |
RuntimeService | 操作流程实例 |
TaskService | 操作任务 |
IdentityService | 操作用户、租户或者组 |
HistoryService | 查询历史表相关数据 |
AuthorizationService | 授权相关服务 |
FormService | 操作流程表单 |
ManagementService | 执行cmd以及job相关服务 |
CaseService | CMMN(管理流程)相关操作 |
FilterService | 过滤相关服务 |
ExternalTaskService | 外部任务相关服务 |
DecisionService | DMN(决策流程)相关服务 |
开始流程:
runtimeService.startProcessInstanceByKey("key");
查询历史流程:
historyService.createHistoricProcessInstanceQuery().list();
设置表单属性:
ProcessInstance instance = runtimeService.startProcessInstanceByKey(key, new HashMap<>());
runtimeService.setVariable(instance.getId(), "key", "value");
同意审批:
Task task = taskService.createTaskQuery().singleResult();
String comment = "同意";
taskService.createComment(task.getId(), task.getProcessInstanceId(), comment);
taskService.complete(task.getId());
退回审批任务:从当前审批任务,退回到已审批的一个或多个任务节点。退回后,已审批节点重新生成审批任务
runtimeService.createProcessInstanceModification(instanceId)
.cancelAllForActivity(activeTask.getTaskDefinitionKey())
.setAnnotation("重新执行")
.startBeforeActivity(curr.getTaskDefinitionKey())
.execute();
3. 服务任务接入方式
- External(外部服务):外部服务订阅消息,服务需加@ExternalTaskSubscription(“topicName”)注解,一般用于复杂的外部系统
- Java class(类):执行java代码,如:com.lt.camunda.ClassName
- Expression(表达式):执行EL表达式 ,可直接调用JavaBean 的方法
- Delegate Expression:基本使用和Expression 使用方式类似,支持EL表达式,也可以直接使用Bean名称,如:${Component}
- HTTP Connector(连接器):用于与外部系统或服务交互(HTTP Client),一般用于简单的接口请求,该方式需要Camunda8支持
4. 执行监听器(Execution Listener)
执行侦听器在流程执行过程中发生某些事件时执行外部Java代码或计算表达式。可以用在任何任务中,可以捕获的事件有:
- 流程实例的开始和结束。
- 进行过渡。
- 活动的开始和结束。
- 网关的开始和结束。
- 中间事件的开始和结束。
- 结束开始事件或开始结束事件
监听器需要实现以下接口:
- 用户任务(UserTask)的监听器为TaskListener
- 服务任务(ServiceTask)的监听器为JavaDelegate
- 其他任务的监听器为ExecutionListener
public class ExampleExecutionListenerOne implements ExecutionListener {
public void notify(DelegateExecution execution) throws Exception {
execution.setVariable("variableSetInExecutionListener", "firstValue");
execution.setVariable("eventReceived", execution.getEventName());
}
}
4.高级用法
1.多租户
Camunda提供以下方式隔离租户:所有租户的数据都存储在一个表中,通过存储在列中的租户标识符(tenant_id)提供隔离
Camunda提供了IdentityService用于租户、用户、组的数据隔离
identityService.saveTenant(); //创建租户
identityService.saveUser(); //创建用户
identityService.saveGroup(); //创建组
查询和插入数据时需要传入tenantId,Camunda目前没有提供类似mp的拦截器
runtimeService.createEventSubscriptionQuery()
.tenantIdIn("1")
.activityId("Event_18iv48j")
.singleResult();
2.多版本控制
有时候我们想修改一个运行中的流程,如果另起一个新流程,就不容易统计之前那个流程的数据,如果将所有版本都放一个流程中,通过流程ID去查询历史数据,会让统计变得很方便。
Camunda流程引擎可以提供版本控制,它满足以下规则:
- 如果重新部署已部署的流程定义,将在数据库中获得一个新版本。
- 正在运行的流程实例将继续在它们启动时的版本中运行。
- 新流程实例将在新版本中运行,除非明确指定。
- 在一定限度内支持将流程实例迁移到新版本。
发起流程实例时:
- By key :它使用密钥启动流程定义的最新部署版本的实例。
- By id:它使用数据库 id 启动已部署流程定义的实例。通过使用它,可以启动特定版本。
3.流程事务(Transaction)
Camunda使用乐观锁提高事务的并发量,一次流程里的节点要么都执行成功,要么都失败。
当流程走到用户任务、时间等待节点等,事务会先将数据持久化到数据库,这个状态被称为“事务的边界“。可以使用“异步延续”的机制打破边界,如果使用则会创建第二个事务,之后的流程如果失败并不会让流程回滚;如果不使用,默认就会回滚到成功的那个节点位置。
4.异步任务
当一个流程中需要处理的任务很多且可并行处理时候,这时候就可以引入异步任务,以提高系统的吞吐量和可伸缩性,实现流程:
- 配置异步处理方式
使用异步服务任务时,需要在服务任务的配置中设置“asynchronousBefore” 和 “exclusive” 属性。其中,”asynchronousBefore”属性用于指定在服务任务执行之前是否启动异步处理,而 “exclusive” 属性用于控制任务的并发性。设置 “exclusive” 属性为 false时,可以允许多个任务并发执行。 - 配置异步处理器
异步任务执行完成后,需要通过异步处理器来处理任务的结果。在 Camunda中,异步处理器使用 Job Executor 来实现。Job Executor 是一个定时任务调度器,用于定时扫描任务队列,并执行异步任务。 - 配置任务重试机制
在异步任务执行过程中,可能会发生各种异常,例如网络故障、超时等。为了保证任务的可靠性和稳定性,通常需要配置任务重试机制。在Camunda 中,可以配置重试次数、重试间隔、重试策略等参数,以满足不同的业务需求。 - 配置异步任务监听器
在异步任务执行过程中,可能需要监听任务的执行状态,例如任务执行成功或者失败等。可以在任务节点上配置任务监听器,监听任务的执行状态,并进行相应的处理。
5.历史数据存储级别
full:所有历史数据都会保存,包括变量的更新
audit(建议):只有历史的流程实例、活动实例、表单数据会被保存
auto:默认audit
none:不存储历史数据
6.流程引擎高可用
实际生产环境中流程引擎一般处于整个业务流程的核心地位,一旦服务不可用,整个系统可能无法提供正常服务。因此,引擎高可用方案在整个SAAS系统中是必不可少的一环。
Camunda7目前提供多实例共享一台数据库模式,性能一般可以得到保证,因为:
- 运行时数据和历史数据分离,且运行时数据会在流程运行完删除
- 只有历史数据的量会大,但可以设置数据有效期,且不影响运行时数据处理的效率