activiti源码解析系列3 - 命令拦截器责任链

activiti之命令拦截器责任链源码分析

查看ProcessEngineConfigurationImpl类的init方法里调用了命令相关的初始化

public void initCommandExecutors() {
    initDefaultCommandConfig();//初始化命令默认配置(主要设置事务类型)
    initSchemaCommandConfig();//schema命令配置(设置schema操作不支持事务)
    initCommandInvoker();//命令拦截器(用于命令调用),初始化CommandInvoker
    initCommandInterceptors();//初始化拦截器列表
    initCommandExecutor();//初始化拦截器链关系及构建命令执行器
}

我们看一下拦截器链的构建

//拦截器初始化
  public void initCommandInterceptors() {
    if (commandInterceptors == null) {
      commandInterceptors = new ArrayList<CommandInterceptor>();
      if (customPreCommandInterceptors != null) {
          //自定义前置拦截器
        commandInterceptors.addAll(customPreCommandInterceptors);
      }
      //默认的拦截器
      commandInterceptors.addAll(getDefaultCommandInterceptors());
      if (customPostCommandInterceptors != null) {
          //后置拦截器
        commandInterceptors.addAll(customPostCommandInterceptors);
      }
      //加入命令调用拦截器
      commandInterceptors.add(commandInvoker);
    }
  }
  public Collection<? extends CommandInterceptor> getDefaultCommandInterceptors() {
    List<CommandInterceptor> interceptors = new ArrayList<CommandInterceptor>();
    //加入日志拦截器
    interceptors.add(new LogInterceptor());
    //加入事务拦截器
    CommandInterceptor transactionInterceptor = createTransactionInterceptor();
    if (transactionInterceptor != null) {
      interceptors.add(transactionInterceptor);
    }
    //加入命令上下文拦截器(用于命令上下文的环境依赖创建初始化工作)
    if (commandContextFactory != null) {
      interceptors.add(new CommandContextInterceptor(commandContextFactory, this));
    }
    //加入事务上下文拦截器(用于session事务的提交和回滚)
    if (transactionContextFactory != null) {
      interceptors.add(new TransactionContextInterceptor(transactionContextFactory));
    }
    return interceptors;
  }
  public void initCommandExecutor() {
    if (commandExecutor == null) {
        //初始化拦截器链关系并构建命令执行器(入口)
      CommandInterceptor first = initInterceptorChain(commandInterceptors);
      commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
    }
  }

在默认的拦截器链的前后可以加入我们自定义扩展的拦截器。

默认的拦截器主要有:

1、日志拦截器

LogInterceptor:每个命令类调用前后会输出日志

2、事务拦截器

(1)SpringTransactionInterceptor

  通过spring的 TransactionTemplate设置事务隔离级别并在事务里执行下一个命令操作

 如下:         

transactionTemplate.setPropagationBehavior(getPropagation(config));//设置事务隔离级别(基于commandConfig中的隔离级别)
T result = transactionTemplate.execute(new TransactionCallback<T>() {
   public T doInTransaction(TransactionStatus status) {
        return next.execute(config, command);
   }
});

 (2)JtaTransactionInterceptor(暂不解析jta)

3、命令上下文拦截器

CommandContextInterceptor

通过command创建命令上下文,包含:

   command命令,sessionFactory,agenda,failedJobCommandFactory失败任务命令工厂,

   closeListeners关闭命令监听器列表,involvedExecutions(当前命令上下文参与执行的执行对象),resultStack(结果栈)等。

并压入Context上下文栈中,若命令上下文不可重用(默认不可重用),则在finally执行命令上下文的关闭操作,并对当前上下文栈等进行回收。

如下代码:

} finally {
      try {
        if (!contextReused) {
          context.close();//当命令执行完可执行一些job等操作
        }
      } finally {
         
        // Pop from stack
        Context.removeCommandContext();//回收命令上下文
        Context.removeProcessEngineConfiguration();//回收配置引用
        Context.removeBpmnOverrideContext();//(流程定义id:ObjectNode)缓存
        Context.removeActiviti5CompatibilityHandler();
      }
    }

接下来看CommandContext的close操作:

public void close() {
    //此方法的目的是正确关闭所有资源,即使在会话或事务上下文的关闭或刷新方法中发生异常也是如此。
    // The intention of this method is that all resources are closed properly, even if exceptions occur
    // in close or flush methods of the sessions or the transaction context.
    try {
      try {
        try {
          executeCloseListenersClosing();
          if (exception == null) {
            flushSessions();//刷空session
          }
        } catch (Throwable exception) {
          exception(exception);//异常输出
        } finally {
          try {
            if (exception == null) {
              executeCloseListenersAfterSessionFlushed();//session清空后执行关闭后置监听器集合
            }
          } catch (Throwable exception) {
            exception(exception);//异常输出
          }
          if (exception != null) {
            logException();
            executeCloseListenersCloseFailure();//执行关闭失败后只监听器集合
          } else {
            executeCloseListenersClosed();//后置执行异步任务
          }
        }
      } catch (Throwable exception) {
        // Catch exceptions during rollback
        exception(exception);
      } finally {
        // Sessions need to be closed, regardless of exceptions/commit/rollback
        closeSessions();//关闭session
      }
    } catch (Throwable exception) {
      // Catch exceptions during session closing
      exception(exception);
    }
    if (exception != null) {
      rethrowExceptionIfNeeded();
    }
}

主要用于关闭前置closing监听器的执行,session的flush, 命令上下文关闭后置Closed监听器的执行,session的close关闭。

4、事务上下文拦截器

TransactionContextInterceptor

构建transactionContext传入listener用于事务的提交和回滚

相关代码:

if (transactionContextFactory != null && !isReused) {//不可重用
    TransactionContext transactionContext = transactionContextFactory.openTransactionContext(commandContext);
    Context.setTransactionContext(transactionContext);
    commandContext.addCloseListener(new TransactionCommandContextCloseListener(transactionContext));
}
return next.execute(config, command);

会往CommandContext加入addCloseListener,listener相关代码:在命令上下文的close操作时调用,用于事务的提交和回滚

@Override
  public void afterSessionsFlush(CommandContext commandContext) {
    transactionContext.commit();
  }
  @Override
  public void closed(CommandContext commandContext) {
     
  }
  @Override
  public void closeFailure(CommandContext commandContext) {
    transactionContext.rollback();
  }

5、CommandInvoker

execute用于命令的最终执行。(通过Agenda计划任务线程链表,可参考agenda源码解析章节

上面几个拦截器的执行步骤:

(1)log拦截器

(2)在事务拦截器里的doInTransaction调用next调用命令上下文拦截器。(保证后面的所有操作都在事务里操作)

(3)命令上下文拦截器用于命令上下文的创建及上下文压栈等操作

(4)然后调用next事务上下文拦截器构造事务listener后置操作(用于当前命令上下文 事务的提交和回滚)。

(5)CommanInvoker用于命令操作的最终执行调用。

(6)在步骤3命令上下文拦截器的后置finally操作里通过步骤4的listener进行事务的刷出缓冲,提交和回滚等。

通过initCommandExecutor()构建的命令执行器CommandExecutorImpl,在该类里进行了命令责任链的first及后续调用执行。在基本activiti提供的所有service方法接口里就是通过命令传入该命令执行器进行后续的执行和调用。

Activiti社区交流群:839915498

更多activiti系列教程:activiti教程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
01-课程计划02-Activiti工作流概念(使用程序演示工作流执行)03-Activiti介绍04-准备Activiti开发环境05-准备开发环境(配置文件)和核心API的介绍06-Activiti入门程序HelloWorld演示流程的执行07-流程定义的CRUD(上)08-流程定义的CRUD(下)09-流程实例,任务,执行对象控制流程的执行(上)10-流程实例,任务,执行对象控制流程的执行(下)11-流程变量(上)12-流程变量(下)13-流程历史数据查询14-第一天知识点回顾15-连线16-排他网关17-并行网关18-流程实例开始结束19-接收任务活动(receiveTask)20-个人任务分配(三种方式)21-组任务分配(三种方式)22-工作流提供的用户角色组(IdentityService)23-项目框架搭建(Struts)24-请假流程管理系统框架搭建(Spring+Struts)25-请假流程图26-知识点回顾27-系统登录(Session)28-自定义拦截器实现Session验证29-部署流程定义(zip文件部署)30-流程定义和部署对象查询31-查看流程图和删除流程定义32-请假单业务的查询列表和新增保存33-请假单业务的编辑保存和删除34-申请请假(启动流程实例)35-查找正在执行的个人任务列表36-使用类动态指定下一个任务的办理人37-办理任务(获取任务节点form key中的值)38-办理任务(使用任务ID,查询请假单)39-办理任务(使用任务ID,查询任务完成后的连线名称集合)40-完成任务41-查询办理任务时操作的历史批注信息(上)42-查询办理任务时操作的历史批注信息(下)43-在请假单中查询历史批注信息(使用请假单ID查询)44-查看当前流程图和课程总结

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值