β

Activiti流程引擎分析

点我达技术 48 阅读

1 前言

Activiti流程引擎分析

工作流是对工作过程中固有程序的流转提出的一个概念,实质是通过将工作活动分解定义良好的任务、过程、角色和规则来进行执行和监控,达到提高生产组织水平和工作效率的目的。工作流能够很好地拆分出任务以及对应地权限,能够以流程图的形式很直观的展现流程任务之间的流转。目前点我达的dms系统也选用流程引擎完成任务流转以及权限控制。市面上有很多工作流引擎可以选择,暂不做介绍,仅针对Activiti流程引擎做分析。

2 Activiti介绍

Activiti其核心是BPMN 2.0的流程引擎。是由jBPM的创建者Tom Baeyens离开JBoss之后建立的项目。Activiti流程引擎使用非常简单,只需要引入Activiti的starter包,就能自动在数据库中创建所需要的表,轻松使用工作流。

3 Activiti模块

Activiti主要分为以下几个模块:
Activiti流程引擎分析

RepositoryService

Activiti中不同版本的业务流程都要有不同的定义信息。RepositoryService提供了对获取这些信息的支持。对应数据库中act_re_开头的表的操作:
act_re_deployment:表示流程的部署信息,每当流程图发生改变时,都会进行重新部署,对应流程的版本号会增加
act_re_model:表示流程设计模型部署
act_re_procdef:存放流程定义的信息,当流程发生变化时,会新生成一条记录

HistoryService

该模块用于获取已经完成的流程的信息(RuntimeService获取运行时流程的信息,两个服务对应的表结构基本相同)。当流程关闭或开启时,会将运行时流程信息同步到act_hi 开头的表中.该服务只能用于流程信息的历史查询,提供很多封装好的查询接口,但不能对历史数据进行修改和删除。
act_hi_actinst:这个表用于流程的历史节点查询,也就是这个流程在结束之前走过那些节点。
act_hi_attachment:历史附件表
act_hi_comment:历史审核意见表,每个流程节点都可以写入审核意见
act_hi_detail:历史流程的详细信息
act_hi_identitylink:用于存储历史流程的发起人以及每个节点的审核人与流程和节点的对应关系
act_hi_procinst:用于记录流程的实例id、流程类型以及版本、发起时间和结束时间等。额外提供了一个BUSINESS
KEY 字段可以用来自定义扩展,比如流程实例id是随机递增生成的,无法形成有序的排列序号,我们可以使用businness key字段来代替实例id,将该字段的生成方式重新定义。
act_hi_taskinst:记录历史流程的节点信息,例如流程类型、版本、节点名称、开始时间和结束时间等
act_hi_varinst:用于记录历史流程的流程变量

TaskService

该服务对执行节点进行查询。在Activiti中业务流程中的每个执行节点被称为Task,对于流程中的数据存取和状态变更等操作均要在Task中完成。Task Service提供了对用户Task相关的操作。它提供了运行时任务查询、领取、完成、删除以及变量设置等功能。

IdentityService

该服务提供了用户和用户组的管理,提供新增、删除、修改用户和用户组的操作。在Activiti中配置执行节点时必须设置接收的候选人,否则该流程将出现“丢失”的情况。在流程流转到下一个执行节点时,会将设置的候选人作为接收对象。操作涉及的数据库表的前缀为act_id_,具体表为:
act_id_group:用户组信息表
act_id_info:用户扩展信息表
act_id_membership:用户和用户组关系表
act_id_user:用户表

RuntimeService

在Activiti中当被定义的业务流程被启动时会创建一个流程实例对象,而RuntimeService提供针对运行时流程的诸多操作,比如启动流程、查询流程实例信息、设置或获取流程变量、删除或增加候选人等操作。对应数据库的表为act_ru_开头的表,表结构基本与act_hi_的表类似,就不做重复介绍了。

流程变量:流程变量作用于整个流程,可以在任何节点上获取,可以在任何节点进行设置。同时流程的流转以及跳转都是根据配置的流程变量的值进行选择不同的执行节点。由于流程信息和业务信息是隔离的,要想根据业务字段来查询流程,可以根据流程变量来进行查询。

Activiti流程图构建

由于idea的Activiti插件使用并不友好,目前推荐eclipse的Activiti插件Activiti BPMN 2.0 designer。流程图画好之后会生成后缀为.bpmn的文件,流程引擎会根据这个文件加载定义的流程图。Activiti有很多种加载方式,比如classpath、inputStream、字符传、zip等压缩包格式进行加载。在dms系统中我们选用zip加载方式。在配置文件中加入 spring.activiti.process-definition-location-suffixes=**.bpmn.zip 。在源码中 org.activiti.engine.repository.DeploymentBuilder 定义了加载的方式。

Activiti启动和部署分析

Activiti从activiti-engine包下的DbSchemaCreate类中开始启动,其中main方法中有这样一行代码。
ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault().setDatabaseSchemaUpdate(ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_CREATE) .buildProcessEngine();
表示Activiti跟随项目启动时进行创建流程引擎。追踪buildProcessEngine方法,我们会在SpringProcessEngineConfiguration类中找到

    public ProcessEngine buildProcessEngine() {
        ProcessEngine processEngine = super.buildProcessEngine();
        ProcessEngines.setInitialized(true);
        autoDeployResources(processEngine);
        return processEngine;
    } 

其中 ProcessEngine processEngine = super.buildProcessEngine(); ,对流程引擎进行初始化。 autoDeployResources 方法中对所有获取的流程图进行部署。接着往下走,在DefaultAutoDeploymentStrategy类中的deployResources方法中,这里描述了当流程图文件以何种方式进行加载。

···
if (resourceName.endsWith(".bar") || resourceName.endsWith(".zip") || resourceName.endsWith(".jar")) {  
    deploymentBuilder.addZipInputStream(new ZipInputStream(resource.getInputStream()));
} else {
   deploymentBuilder.addInputStream(resourceName, resource.getInputStream());
}
···
deploymentBuilder.deploy();  

这段代码表明根据资源的后缀判断加载方式,目前提供压缩包和inputStream两种方式加载。deploymentBuilder.deploy()方法中实际是调用RepositoryService服务进行发布的。

public Deployment deploy() {  
    return repositoryService.deploy(this);
}

追踪到deploy方法中发现Activiti采用命令模式进行设计,具体执行逻辑为 commandContext.getProcessEngineConfiguration().getDeploymentManager().deploy(deployment, deploymentSettings); 继续往下走,真正执行部署逻辑的是BpmnDeployer类的deploy方法。该方法主要是针对加载的资源进行解析、加载、缓存、入库等操作。由于代码过长就不展示了,有兴趣的同学可以对源码进行解读。

Activiti扩展

当Activiti提供的api无法满足业务要求时,如何扩展?

通过上面的分析我们可以发现,Activiti的操作实质是对数据库表的查询和修改。因此当api不满足业务要求时我们可以手写查询语句等来替换原有api,同时也要求开发人员对Activiti的二十多张表要有清楚的认知。此外,Activiti也预留了方便于手写SQL语句的方式。以查询为例子,HistoryService提供NativeHistoricProcessInstanceQuery类支持手动编辑SQL,RuntimeService也提供了NativeProcessInstanceQuery等。

Activiti如何替换已有的流程图?

这个问题产生的原因是当流程已经运行一段时间产生很多未完成流程时,发现流程图有错误,需要修改流程图,并且希望以前产生的流程都能按照新的流程图进行处理。Activiti机制中如果流程图发生变化重新部署时,流程图的版本号会增加。这是为了在流程图发生变化的时候,未完成流程能够按照原先流程继续流转,而新流程能够按照新的流程图进行处理。这时候需求和Activiti的机制发生冲突。根据上文介绍的,Activiti对于版本和流程定义在数据库act_re 为前缀的表中操作。根据之前的介绍,act_re_procdef存放流程的定义,act_ge_bytearrary用于存放流程图的二进制信息。首先将旧流程图的act_ge_bytearrary表数据删除,将新流程图的act_re_procdef表数据删除,然后将新流程图的act_ge_bytearrary表数据里的DEPLOYMENT ID 修改成旧流程图act_re_procdef表数据的DEPLOYMENT ID_。
注意:这种方式仅限于微小改动,不能修改原有的流程的执行节点的重要数据,否则会导致原有流程出错。

如何使用自定义流程id?

有时业务方希望流程id具有某种实际意义,比如说创建时间+流水号的形式展现,以便于他们统计当天流程数量等等。显然流程id在流程引擎中至关重要,首先就必须保证其唯一性。基于需求方的要求修改流程id的生成方式可能有时无法保证绝对唯一,导致流程创建错误。此时Activiti提供了额外的business key字段可以用于业务处理。我们只要改写business key字段的生成方式满足业务要求。此外,RuntimeService也提供了根据business_key作为查询条件的接口。

小结

由于在dms系统使用了Activiti作为流程引擎,所以针对Activiti做了一些分析。以上介绍了Activiti相应的模块以及数据库对应表的含义,针对启动过程做了简单的分析。有些讲的不对的地方,还请多多指正。

参考文章

参考文章-Activiti介绍

作者:点我达技术
<h2 id="">前言</h2> <p>在上一篇文章<a href="http://blog.5udou.cn/blog/You-formBiao-Dan-Lai-Shuo-Shuo-Qian-H
原文地址:Activiti流程引擎分析, 感谢原作者分享。

发表评论