流程引擎Activiti使用的思考
目录:
1、Activiti的常用功能
2、Activiti会签功能的使用及缺陷
3、统计的需求使得同步流程数据到业务数据库
4、最终方案:建立node信息接管Task
---------------------------------------我是传说中分割线------------------------------------------
一、Activiti的常用功能
其实Activiti的功能非常强大,但我们在创建项目时使用的都是Activiti的一些常用功能,很简单,在此也做一个总结吧。
1、常用的service
<bean id="repositoryService" factory-bean="processEngineFactory" factory-method="getRepositoryService" />
<bean id="runtimeService" factory-bean="processEngineFactory" factory-method="getRuntimeService" />
<bean id="formService" factory-bean="processEngineFactory" factory-method="getFormService" />
<bean id="identityService" factory-bean="processEngineFactory" factory-method="getIdentityService" />
<bean id="taskService" factory-bean="processEngineFactory" factory-method="getTaskService" />
<bean id="historyService" factory-bean="processEngineFactory" factory-method="getHistoryService" />
<bean id="managementService" factory-bean="processEngineFactory" factory-method="getManagementService" />
结合spring,将activiti常用的service注入到spring容器中,方便调用。
repositoryService--主要用于发布自定义流程到数据库中
runtimeService--主要用于启动流程
taskService--主要用于流转任务等相关任务的操作,这个service最重要!!!
historyService--主要用于查询一些历史信息
2、常用操作
2.1 发布流程
Deployment deployment = repositoryService.createDeployment()
.name("process_name")
.addClasspathResource("process_path")
.deploy();
2.2 开启流程
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(process_id, map);
2.3 领取任务
taskService.claim(taskId, userId);
2.4 流转任务
taskService.complete(taskId, map);
2.5 流程监听
特别说明一下这个流程监听,由于我们的项目比较注重各任务节点的状态,所以这个监听就特别重要,可以在监听中做各种操作,而不必在外面来进行处理状态的修改。
同时使用监听对整个代码分层很有好处,就是在外面的service只需要准备数据,将准备的数据传入到监听中,由监听来完成业务数据的存储,这样整个结构很清晰,方便开发和运维。
@Service
public class CsMonitorConfirm implements TaskListener{
@Override
public void notify(DelegateTask delegateTask) {
...
}
}
二、Activiti的会签功能及使用缺陷
首先说明一下,这个会签功能很强大,使用多实例创建多个任务操作很方便,只需要在流程图中进行配置及可。
具体的实现可以参考另外一篇文章:Activiti多级会签实现
这里说明一下:
本来之前的这个方案是可以,但后面我们的项目又提出需要进行动态添加人员再次会签的操作。解释一下:
比如流程流转到A节点,A节点流转到B节点时进行了会签操作,分发了3个人;然后A节点可以再次分发3个人,这种情况Activiti就不支持了,因为一次分发的情况,其实在A节点的任务已经complete了;
只能说中国式的这种思维太蛋疼了,之前还在网上看到过无记录撤销,反正各种种种,不符合Activiti的设计理念。
但没办法呀,项目还得做,咱们就是小工一枚
三、数据库同步问题
由于业务需要,统计功能也是必需的。因此对于数据的采集就出现了问题。
3.1 统计同时需要流程数据和业务数据
我们在设计整个项目架构时,流程数据表和业务数据表并没有放到一个数据库下(分库存储,这样风险小些,维护也要方便些)--最初是考虑的是放到一个数据库的不同schema下,但最终没有被采纳。因此2个数据库的通信问题就很麻烦了(DbLink感觉不是很好用)
3.2 将统计的流程数据同步到业务数据库中
我们在设计时,新增了一张node表,第一个流程task都会在node表中新增一条记录,这条记录用来记录下此task的流程相关的一些数据(比如开始、领取、结束时间,处理人员)和业务相关的关联数据,以此来方便日后的查询。
通过这张表,我们统计的时候就完全不用到2个数据库中去查询了,解决了数据库之前的通信问题,提高了统计效率。
四、最终方案
4.1 针对会签无法解决的需求,我们只能自己使用业务表来进行模拟流程操作
这种模拟操作感觉特别麻烦,虽然能够实现功能,但破坏了数据存储的统一性。因此我们借助于之前提交到node表来存储虚拟流程数据,这样就存储统一了。
不管是真实流程数据还是虚拟流程数据,每进行一次流转,都在node表中产生一条记录,以node表来代替流程引擎中的task表。任务流转时,通过node表进行判断从而是使用Activiti进行流转还是虚拟流转。将真实任务和虚拟任务完全统一到node表中。
4.2 任务参与人问题
由于虚拟任务没有经过流程引擎,而真实任务是经过了流程引擎的--任务参与人在Activiti中是有记录的。
对此,我们创建一张pending表,将所有当前活动任务参与人都记录到此表中
使用node表的主键与参与人关联记录。这样我们在业务上去查询处理人时,也完全从流程数据库中剥离出来了。
4.3 项目中剥离流程引擎数据库
通过node表的记录,我们项目在做查询时,只会访问业务数据库,而不用去关心流程引擎的数据库。而流程数据库只负责真实任务的流程流转。node表良好地接管了task的功能。
记录一个小问题:
在设置变量时,针对setVariable时,尽量不要设置成复杂对象,因此activti会序列化此对象,当你再次getVariable时,如果你的实体类发生了改变,反序列化时就会报错。当然针对一些瞬时变量,这个是没有问题的,这个特别注意一下。
--------------------------------------------------分割结束-----------------------------------------------------
以上是我在使用Activiti的一些思考,这种设计模式不一定最好,也希望各位大神们指导交流。