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 条评论
登录 后参与评论

相关文章

来自专栏NetCore

Catalog Service - 解析微软微服务架构eShopOnContainers(三)

上一篇我们说了Identity Service,因为其基于IdentityServer4开发的,所以知识点不是很多,今天我们来看下Catalog Service...

3028
来自专栏拂晓风起

Loader拉取图片,由于redirect重定向,导致策略文件无效 设置checkPolicyFile后还是无效:需要一个策略文件,但在加载此媒体时未设置 checkPolicyFile 标志

1096
来自专栏小白安全

Windows-Exploit-Suggester --- Windows下提权辅助工具

此工具是一款非常好用的Windows下提权辅助工具(已经支持Windows 10下的提权了),国内已经有许多人在用了,但是一直没有相应的中文文档,所以我特地...

3015
来自专栏何俊林

Android支付实践(三)之银联支付功能(客户端+服务端)

前言:由于支付宝和微信支付都须要提供这个那个的认证材料,对于个人开发者想尝试,确实有不少麻烦,今天介绍的银联支付,对于个人开发者,可以说是福音了。来自chent...

8388
来自专栏信安之路

RedTeam 技巧集合

1、利用目标用户使用的 user agent 来隐藏自身的恶意流量,比如像 Outlook 软件的 UA。

1432
来自专栏写写代码吃吃瓜

Android调试神器stetho使用详解和改造

3606
来自专栏Eugene's Blog

黑客常用的扫描器盒子分类目录文章标签友情链接联系我们

2649
来自专栏FreeBuf

XSS的原理分析与解剖:第三章(技巧篇)

作者 Black-Hole 0×01 前言: 关于前两节url: 第一章:http://www.freebuf.com/articles/web/40520....

1987
来自专栏张戈的专栏

HTTP加速器varnish安装小记(1)

上午共享的那个varnish 安装手册,个人看了下,有点不知所云,好吧~看来还是先安装玩玩! 苦逼公司服务器没法连外网,不能用什么 wget 或 yum 命令直...

3348
来自专栏蓝天

C/C++编程可用的Linux自带工具

GNU Binary Utilities或binutils是一整套的编程语言工具程序,用来处理许多格式的目标文件。当前的版本原本由在Cygnus Soluti...

1302

扫码关注云+社区

领取腾讯云代金券