专栏首页kl的专栏Activiti工作流杂谈-工作机制详解
原创

Activiti工作流杂谈-工作机制详解

前言碎语

以下内容为博主在公司内部分享的一个小文档,谈到了activiti的各方面内容,有需要的可留言要word原文件 

Activiti工作流分享

分享或多或少都要有所收获,无论分享者或听众,大家聚在一起,集思广益,或收获一个关键字,一种新技术,一种新的理解,一种新的视角,分享的意义即在于此,下面,为了使分享的意义最大化,请允许我花一两分钟时间讲下和技术无关的题外话

受众分类

1.没用过没了解过的:我尽量事无巨细,点点讲清楚,有疑问,多问多提

2.了解过用过没深入的:突出详解api相关以及容器怎么加载activiti怎么设计怎么工作,还有activiti数据库表设计

3.用过熟知的:希望纠正错误的理解,补充没谈到的技术细节

关于文档:我会结合工程项目讲解,代码内容都在演示工程里,就不贴太多源码了,这里简要谈下,其实最好的文档就是官方文档啦

官方文档:http://www.activiti.org/userguide/index.html#

中文文档:http://www.kailing.pub/PdfReader/web/viewer.html?file=Activiti5.4Guide

进入正题:

activiti是什么?

是一种工作流引擎。提供对各应用系统有决定作用的根据角色、分工和条件的不同决定信息传递路由、内容等级等核心解决方案。工作流引擎包括了,流程的节点管理、流向管理、流程样例管理等重要功能

通俗点理解+使用场景举例:说白了,就是一个流程管理框架,使业务可以按照设定好的流程走,且可以在线更新业务流程,使程序可以快速适应业务变化发展,使系统更好的维护和扩展,解决了这么一个问题。具体场景的话如,借款审核,报销申报,请假审批等等

怎么集成,关键类,简单使用,ProcessEngineConfiguration相关实现解读

ProcessEngineConfiguration 引擎配置类

org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration:此流程引擎用于独立环境下。Acitviti会处理事务。

org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration:适用于单元测试,Acitviti会处理事务。默认使用H2内存数据库。默认的databaseSchemaUpdat配置为DB_SCHEMA_UPDATE_CREATE_DROP,所以此数据库在流程引擎启动与关闭时进行创建和删除

org.activiti.spring.SpringProcessEngineConfiguration:Spring环境下使用流程引擎的情况下使用。

    protected PlatformTransactionManager transactionManager;
    protected String deploymentName = "SpringAutoDeployment";
    protected Resource[] deploymentResources = new Resource[0];
    protected String deploymentMode = "default";
    protected ApplicationContext applicationContext;
    protected Integer transactionSynchronizationAdapterOrder = null;
    private CollectiondeploymentStrategies = new ArrayList();

相比与官方提供的,spring的实现提供了更多的可配置项,如上,如部署资源数组,部署name,在获取引擎对象的时候,会自动部署我们配置的流程资源,可见如下buildProcessEngine方法的实现

    @Override
    public ProcessEngine buildProcessEngine() {
        ProcessEngine processEngine = super.buildProcessEngine();
        ProcessEngines.setInitialized(true);
        autoDeployResources(processEngine);
        return processEngine;
    }
    protected void autoDeployResources(ProcessEngine processEngine) {
        if (deploymentResources != null && deploymentResources.length > 0) {
            final AutoDeploymentStrategy strategy = getAutoDeploymentStrategy(deploymentMode);
            strategy.deployResources(deploymentName, deploymentResources, processEngine.getRepositoryService());
        }
    }

引擎工具类ProcessEngines

ProcessEngines.getDefaultProcessEngine();

获取引擎

ProcessEngine processEngine = pec.buildProcessEngine();

基础服务类

RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
ManagementService managementService = processEngine.getManagementService();
IdentityService identityService = processEngine.getIdentityService();
HistoryService historyService = processEngine.getHistoryService();
FormService formService = processEngine.getFormService();

手动部署流程

repositoryService.createDeployment().addClasspathResource("hello.bpmn").name("初级审核流程部署").deploy();

启动流程

runtimeService.startProcessInstanceByKey(String processDefinitionKey, Map variables);

任务查询

taskService.createTaskQuery().taskAssignee("boss").list();

处理人工任务

taskService. complete(String taskId, Map variables);

任务事件监听

TaskListener

Activiti工作原理之命令模式+职责链模式?

命令模式:行为请求者”与“行为实现者”相分离

职责链模式(责任链模式):参考filter实现,不多解释

org.activiti.engine.impl.interceptor包下五个关键接口或类

Command 实际命令

CommandConfig 命令执行配置,如事务级别配置

CommandExecutor命令执行器,最终命令执行,包含命令职责链

CommandInterceptor 命令拦截器链接口

CommandInvoker拦截器实现,链的最末端

从三处代码,详解看activiti如何设计

命令执行器如何初始化?

代码在org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl  initCommandExecutors

protected void initCommandExecutors() {
  initDefaultCommandConfig();
  initSchemaCommandConfig();
  initCommandInvoker();
  initCommandInterceptors();
  initCommandExecutor();
}

1和2方法初始化了默认命令执行配置,主要用于事务拦截器命令执行,如SpringTransactionInterceptors事务拦截代码

public class SpringTransactionInterceptor extends AbstractCommandInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(SpringTransactionInterceptor.class);
    protected PlatformTransactionManager transactionManager;
    public SpringTransactionInterceptor(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
    publicT execute(final CommandConfig config, final Commandcommand) {
        LOGGER.debug("Running command with propagation {}", config.getTransactionPropagation());
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        transactionTemplate.setPropagationBehavior(getPropagation(config));
        T result = transactionTemplate.execute(new TransactionCallback() {
            public T doInTransaction(TransactionStatus status) {
                return next.execute(config, command);
            }
        });
        return result;
    }
    private int getPropagation(CommandConfig config) {
        switch (config.getTransactionPropagation()) {//判断CommandConfig配置
            case NOT_SUPPORTED://无事务
                return TransactionTemplate.PROPAGATION_NOT_SUPPORTED;
            case REQUIRED://默认是这个,无事务创建,有就加入
                return TransactionTemplate.PROPAGATION_REQUIRED;
            case REQUIRES_NEW://无事务创建,有就将老事务挂起
                return TransactionTemplate.PROPAGATION_REQUIRES_NEW;
            default:
                throw new ActivitiIllegalArgumentException("Unsupported transaction propagation: " + config.getTransactionPropagation());
        }
    }
}

这里谈到事务拦截器多讲一句,ProcessEngineConfigurationImpl类提供了一个抽象的获取事务拦截器的方法createTransactionInterceptor,其他引擎配置类可以重写这个抽象方法,提供自己的事务处理,如org.activiti.spring.SpringProcessEngineConfiguration引擎配置类处理如下:

@Override
protected CommandInterceptor createTransactionInterceptor() {
    if (transactionManager == null) {//transactionManager是自己配置的
        throw new ActivitiException("transactionManager is required property for SpringProcessEngineConfiguration, use "
                + StandaloneProcessEngineConfiguration.class.getName() + " otherwise");
    }
    return new SpringTransactionInterceptor(transactionManager);
}

3初始化命令执行者,也是一个拦截器,会被放在拦截器链的末端

4初始化拦截器,会添加用户自定义的前置拦截器集合(customPreCommandInterceptors)和后置拦截器集合(customPostCommandInterceptors),前置后后置是相对于activiti默认的拦截器来说的,可见如下代码,所以最后拦截器的顺序是:customPreCommandInterceptors->LogInterceptor->TransactionInterceptor->CommandContextInterceptor->customPostCommandInterceptors->commandInvoker

protected void initCommandInterceptors() {
  if (commandInterceptors==null) {
    commandInterceptors = new ArrayList();
    if (customPreCommandInterceptors!=null) {
      commandInterceptors.addAll(customPreCommandInterceptors);//添加前置拦截
    }
    commandInterceptors.addAll(getDefaultCommandInterceptors());//activiti默认
    if (customPostCommandInterceptors!=null) {
      commandInterceptors.addAll(customPostCommandInterceptors);
    }
    commandInterceptors.add(commandInvoker);
  }
}
protected Collection< ? extends CommandInterceptor> getDefaultCommandInterceptors() {
  Listinterceptors = new ArrayList();
  interceptors.add(new LogInterceptor());
  CommandInterceptor transactionInterceptor = createTransactionInterceptor();
  if (transactionInterceptor != null) {
    interceptors.add(transactionInterceptor);
  }
  interceptors.add(new CommandContextInterceptor(commandContextFactory, this));
  return interceptors;
}

5初始化命令执行器,包含了构建拦截器链的过程,可见代码如下

protected void initCommandExecutor() {
  if (commandExecutor==null) {
    CommandInterceptor first = initInterceptorChain(commandInterceptors);
    commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
  }
}
protected CommandInterceptor initInterceptorChain(Listchain) {
  if (chain==null || chain.isEmpty()) {
    throw new ActivitiException("invalid command interceptor chain configuration: "+chain);
  }
  for (int i = 0; i < chain.size()-1; i++) {
    chain.get(i).setNext( chain.get(i+1) );
  }
  return chain.get(0);
}

相关Service服务怎么执行?

public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map variables) {
  return commandExecutor.execute(new StartProcessInstanceCmd(processDefinitionKey, null, null, variables));
}

上面是runtimeService启动流程的方法内部结构,可以看到使用了commandExecutor提交了一个命令。也就是命令模式里面的行为请求者。你可能有疑问,那么命令执行器commandExecutor是何时注入的呢?请往下看

初始化服务

  protected void initServices() {
    initService(repositoryService);
    initService(runtimeService);
    initService(historyService);
    initService(identityService);
    initService(taskService);
    initService(formService);
    initService(managementService);
  }
  protected void initService(Object service) {
    if (service instanceof ServiceImpl) {
      ((ServiceImpl)service).setCommandExecutor(commandExecutor);
    }
  }

最后安利一波设计模式,更高效阅读框架源码,细心的你可能发现了SpringProcessEngin eConfiguration中的自动部署用到了策略者模式,所以设计模式无处不在啊

24种设计模式:http://www.kailing.pub/PdfReader/web/viewer.html?file=24DesignPattern

流程设计简解

what启动事件和结束事件:?

what生产活动?

人工任务:需要人参与完成的工作。当流程执行到这样的用户任务时,会在分配任务的用户或用户组的任务列表中创建新的任务

服务任务:调用外部Java类

what网关?

并行网关(+):执行到该网关,会有多条线路同时并行执行,当都执行完才继续执行后面的;

排他网关(x):执行到该网关,根据条件只能走一条执行线路;

包容网关(o):整合并行网关+排他网关

更多其他流程图相关的内容怎么更好的学习?

建议画流程图的时候相关的节点多拖一拖看一看他的属性,结合文档摸索摸索就差不多了

数据表结构?

Activiti使用到的表都是ACT_开头的。

ACT_RE_*:’RE’表示repository(存储),RepositoryService接口所操作的表。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。

ACT_RU_*:‘RU’表示runtime,运行时表-RuntimeService。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。

ACT_ID_*:’ID’表示identity (组织机构),IdentityService接口所操作的表。用户记录,流程中使用到的用户和组。这些表包含标识的信息,如用户,用户组,等等。

ACT_HI_*:’HI’表示history,历史数据表,HistoryService。就是这些表包含着流程执行的历史相关数据,如结束的流程实例,变量,任务,等等

ACT_GE_*:全局通用数据及设置(general),各种情况都使用的数据。

详细说明每张表:

ACT_EVT_LOG                事件日志

ACT_GE_BYTEARRY            xml, png等二进制内容

ACT_GE_PROPERTY            引擎版本信息

ACT_HI_ACTINST              历史节点

ACT_HI_ATTACHMENT          历史附件

ACT_HI_COMMENT            历史意见表

ACT_HI_DETAIL                历史详情表,提供历史变量的查询

ACT_HI_IDENTITYLINK          历史参与者

ACT_HI_PROCINST             历史流程实例

ACT_HI_TASKINST              历史任务实例

ACT_HI_VARINST               历史变量实例

ACT_ID_GROUP                用户组信息表

ACT_ID_INFO                  用户的人员详细信息

ACT_ID_MEMBERSHIP           用户与群组关系

ACT_ID_USER                  用户的基本信息

ACT_PROCDEF_INFO            流程定义的动态变更信息

ACT_RE_DEPLOYMENT          部署信息表

ACT_RE_MODEL                模型(用于Web Designer)

ACT_RE_PROCDEF               流程定义数据

ACT_RE_EVENT_SUBSCR          事件监听

ACT_RU_EXECUTION             流程实例

ACT_RU_IDENTITYLINK           参与者

ACT_RU_JOB         异步作业

ACT_RU_TASK        任务节点

ACT_RU_VARIABLE    流程变量

(彩蛋)Spring boot集成activiti,activiti rest服务?

参考另一篇博文:http://www.kailing.pub/article/index/arcid/137.html

最后的最后,深入浅出用一张图片做总结

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于RabbitMQ+Hessian+spring实现远程RPC调用

    对RPC通俗的理解就是,调用远程服务和调用本地服务一样透明化无感知。使用过dubbo和motan的同学肯定有这种感觉。实现RPC调用过程,无非解决两个问题:

    kl博主
  • 深入理解@Transactional的工作原理

    写这篇博文有个来由,是为了解决博主遇到的多数据源的事务问题(用不了JTA),所以深入到spring-tx的源码去学习了一番,非常有收获,最后博主的分布式事务问题...

    kl博主
  • spring-boot-klock-starter分布式锁项目开源

    spring-boot-klock-starter是一个基于redis的分布式锁spring boot starter组件,使得项目拥有分布式锁能力变得异常简单...

    kl博主
  • 在Mockplus中使用标尺和参考线

    1 显示或隐藏标尺和参考线 ? 2 设置标尺选项 ? 3 设置参考线颜色 主菜单 -> 选项 -> 系统 ? 4 添加或删除参考线 ?

    奔跑的小鹿
  • Springboot项目中Freemarker配置无法加载jar中模板的解决办法

    飞奔去旅行
  • 手把手实战Python定制菜谱翻译 | 不到80行代码 !

    在中国的有一些餐馆,菜单上不仅有个中文名,还有英文名,有很专业的翻译,也有让人笑Cry的翻译。配上几张图感受一下。

    叫我龙总
  • 让人头晕的JavaScript隐式强制类型转换

    想要解出这个题目,首先要了解 map 方法和 parseInt。这两个方法在平时使用的频率是很高的,对于 map 方法肯能都很熟悉,经常用它来操作数组,然后返回...

    多云转晴
  • 手把手教你打造 SDN 网路(四) (设定外部联网)

    首先按下 Ctrl+D 登出 root 跟 Ubuntu 回到 Host 之后用 vagrant 指令关掉并且杀掉 VM

    腾讯云TStack
  • TPU的起源,Jeff Dean综述后摩尔定律时代的ML硬件与算法

    过去十年我们见证了机器学习的显著进步,特别是基于深度学习的神经网络。机器学习社区也一直在尝试构建新模型,用于完成具有挑战性的工作,包括使用强化学习,通过和环境进...

    机器之心
  • 无线安全第三篇:进行简易嗅探与会话劫持和防范

    作为一个“有追求”的黑客,小黑又岂会在此时就收手呢?如同很多“菜鸟黑客”一样,小黑想要挖掘出小白更多的秘密。

    网e渗透安全部

扫码关注云+社区

领取腾讯云代金券