activiti-5 核心之CommandContext 转

2023-10-27

 众所周知,从以前的jbpm到现今的activiti,流程引擎的内部执行模式是command模式,不管是启动流程,

 还是推动流程等等,
 
 都采用了command的execute方法。
 
 而command执行依赖于CommandContext,直译就是command的上下文,那么,
 
 我们就来看看CommandContext里面的内容。

 首先是CommandContext本身的类变量和实例变量:

 

private static Logger log = Logger.getLogger(CommandContext.class.getName());

private static final ThreadLocal<Stack<CommandContext>> txContextStacks = new 	ThreadLocal<Stack<CommandContext>>();

protected Command< ? > command;

protected TransactionContext transactionContext;

protected Map<Class< ? >, Session> sessions = new HashMap<Class< ? >, Session>();

protected Throwable exception = null;

protected ProcessEngineConfigurationImpl processEngineConfiguration;

 

 

 其实从这个变量声明,我们就能够大致看出CommandContext的管辖范围,
 
 首先是提供线程安全的副本栈txContextStacks,然后是在当前上下文执行的command,
 
 事务上下文transactionContext,会话集合sessions ,流程引擎配置类processEngineConfiguration,
 
 至于log和exception肯定就不用说了。当然,实际来说,transactionContext其实只是为session管理服务的,稍后可见。

 为了避免线程冲突,每个command都在一个独立的commandContext中执行,如下:

 

 

  public static void setCurrentCommandContext(CommandContext commandContext) {

    getContextStack(true).push(commandContext);

  }

 

  public static void removeCurrentCommandContext() {

    getContextStack(true).pop();

  }

 

  public static CommandContext getCurrent() {

    Stack<CommandContext> contextStack = getContextStack(false);

    if ((contextStack == null) || (contextStack.isEmpty())) {

      return null;

    }

    return contextStack.peek();//在非出栈情况下获取栈顶的CommandContext

  }

 

  private static Stack<CommandContext> getContextStack(boolean isInitializationRequired) {

    Stack<CommandContext> txContextStack = txContextStacks.get();//获取当前线程一个栈变量副本

    if (txContextStack == null && isInitializationRequired) {//初始化栈

      txContextStack = new Stack<CommandContext>();

      txContextStacks.set(txContextStack);

    }

    return txContextStack;

  }

 

 

 

 看到这里,大家可能会产生一个疑问,ThreadLocal为啥限定类型为Stack,而不是Map之类的Collection呢?
 
 其实,在了解了command的执行过程后,就不会有这个问题了。

 一个command在生成之后交由CommandExecutor执行时,要经过一个CommandInterceptor,
 
 这个拦截器做了什么呢?它会使用一个CommandContextFactory为这个command生成
 
 【commandContextFactory.createCommandContext(command)】并指定【CommandContext.setCurrentCommandContext(context)】
 
 一个CommandContext,然后CommandExecutor执行command,执行完毕后,
 
 CommandInterceptor再将指定的CommandContext关闭【context.close()】并移除【CommandContext.removeCurrentCommandContext()】。
 
 在这个过程中我们可以看到,CommandContext的生成和移除正好对应了入栈和出栈,简单来说,就是
 
 创建CommandContext--执行command--移除CommandContext 这样一个过程,
 
 这个生命周期用栈来管理正是天作之合,如果用collection,势必增加不必要的开销且别扭。

 下面看看CommandContext的关闭,里头干了不少事情啊 

 

写道
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 {



if (exception == null) {

flushSessions();//会话提交

}



} catch (Throwable exception) {

exception(exception);

} finally {



try {

if (exception == null) {

transactionContext.commit();//事务提交

}

} catch (Throwable exception) {

exception(exception);

}



if (exception != null) {

log.log(Level.SEVERE, "Error while closing command context", exception);

transactionContext.rollback();//遇到异常事务回滚

}

}

} catch (Throwable exception) {

exception(exception);

} finally {

closeSessions();//关闭会话



}

} catch (Throwable exception) {

exception(exception);

}



// rethrow the original exception if there was one

if (exception != null) {

if (exception instanceof Error) {

throw (Error) exception;

} else if (exception instanceof RuntimeException) {

throw (RuntimeException) exception;

} else {

throw new ActivitiException("exception while executing command " + command, exception);

}

}

}

 

 如上可见,command执行完毕后的会话、事务和异常都在这儿统一管理了。

 

 之后就是通过map获取会话的一堆代码了:

写道

public <T> T getSession(Class<T> sessionClass) {

Session session = sessions.get(sessionClass);

if (session == null) {

SessionFactory sessionFactory = processEngineConfiguration.getSessionFactories().get(sessionClass);

if (sessionFactory==null) {

throw new ActivitiException("no session factory configured for "+sessionClass.getName());

}

session = sessionFactory.openSession();

sessions.put(sessionClass, session);

}



return (T) session;

}



public RepositorySession getRepositorySession() {

return getSession(RepositorySession.class);

}

public RuntimeSession getRuntimeSession() {

return getSession(RuntimeSession.class);

}

public IdentitySession getIdentitySession() {

return getSession(IdentitySession.class);

}

public MessageSession getMessageSession() {

return getSession(MessageSession.class);

}

public TimerSession getTimerSession() {

return getSession(TimerSession.class);

}

public TaskSession getTaskSession() {

return getSession(TaskSession.class);

}

public HistorySession getHistorySession() {

return getSession(HistorySession.class);

}

public ManagementSession getManagementSession() {

return getSession(ManagementSession.class);

}

public DbSqlSession getDbSqlSession() {

return getSession(DbSqlSession.class);

}

 

 得说一下,这一坨东西看上去真丑陋,不过考虑到这块估计也没什么扩展和改动了,就这样吧。

 

 

原文:http://blog.csdn.net/songry/article/details/5696624

 

www.ibuyincn.com

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

activiti-5 核心之CommandContext 转 的相关文章

随机推荐

  • 小学生机器人编程知识

    小学生机器人编程知识 现在的家长在培养孩子的学习方面也是非常的认真的 会给孩子选择一些能够有利于孩子成长的课程 就拿现在很多的家长给孩子选择少儿编程的课程来说 他们想要孩子去学习机器人编程的课程 但是他们对于小学生机器人编程知识并不是很清楚
  • windows下设置redis服务开机后自动启动

    1 配置环境变量 在path配置环境变量 2 在redis安装目录下打开cmd 输入如下代码 redis server exe service install redis windows conf loglevel verbose 3 这样
  • MAC下搭建Android Studio

    JDK1 8安装 1 到 http www oracle com technetwork java javase downloads jdk8 downloads 2133151 html 下载jdk8 2 双击安装 3 安装完成 在命令行
  • 7-13 日K蜡烛图 (15分)

    7 13 日K蜡烛图 15分 股票价格涨跌趋势 常用蜡烛图技术中的K线图来表示 分为按日的日K线 按周的周K线 按月的月K线等 以日K线为例 每天股票价格从开盘到收盘走完一天 对应一根蜡烛小图 要表示四个价格 开盘价格Open 早上刚刚开始
  • Java复习-20-接口(1)

    接口的定义及使用 如果相对外部隐藏全部的实现细节 就要通过接口来实现 接口的定义 使用interface关键字来定义 由于接口描述的是一个公共的定义标准 所以在接口之中所有的抽象方法的访问权限都为public interface IMess
  • 数据库种类有什么?三种不同数据库介绍

    一 数据库种类有哪些 早期较为时兴的数据库种类有三种 分别是层次式数据库 网络式数据库和关系型数据库 而在如今的互联网中 最常见的数据库种类主要有2种 即关系型数据库和非关系型数据库 二 层次数据库介绍 层次数据库是最开始研制的数据库系统软
  • python获取时间前一天

    可以使用 Python 的 datetime 模块来获取时间前一天的日期 首先 需要导入 datetime 模块 import datetime 然后 可以使用 datetime 模块中的 datetime datetime now 函数获
  • GET、POST、PUT、DELETE等用法

    1 向服务器请求数据 GET get请求是用来获取数据的 只是用来查询数据 不对服务器的数据做任何的修改 新增 删除等操作 get请求会把请求的参数附加在URL后面 2 提交资源到服务器 post post请求一般是对服务器的数据做改变 常
  • so部标协议模拟服务器,808部标协议

    满意答案 豆 浆 2016 10 12 采纳率 58 等级 25 已帮助 62843人 基于部标JT T 808协议及数据格式的GPS服务器 2011年5月10日中国交通通信信息中心下发了 印发道路运输车辆卫星定位系统平台和道路运输车辆卫星
  • python 43行 写一个天气查询爬虫+GUI图形界面化

    这个爬虫爬的是 墨迹天气 https tianqi moji com weather china henan xinxiang 分析了一下这个网址 不同城市的网址就后边的的拼音不同 这时候就只需拼接用户输入的网址就可得到要查询的网址 然后通
  • Putty基础教程之(一).入门命令学习及编写HTML

    这篇文章主要介绍Putty的基础用法 同时通过Putty来编辑HTML文件 一方面是自己最近学习的在线笔记 另一方面希望文章对你有所帮助 Putty是Windows下操作Linux命令的小工具 也是一个跨平台的远程登陆工具 非常好用 常见命
  • 【IT之路】MyEclipse部署java web项目到Tomcat

    1 Java web 项目部署发布到tomcat 2 启动tomcat
  • 测试分布式系统的线性一致性

    测试分布式系统的线性一致性 一 介绍 正确实现一个分布式系统是非常有挑战的一件事情 因为需要很好的处理并发和失败这些问题 网络包可能被延迟 重复 乱序或者丢弃 机器可能在任何时候宕机 即使一些设计被论文证明是正确的 也仍然很难再实现中避免
  • css3弹性盒子模型(Flex)

    css3弹性盒子模型 CSS3 弹性盒子 Flex Box 设置弹性盒子 容器的属性 设置主轴方向 flex direction 设置主轴方向上对齐方式 justify content 设置副轴方向上的对齐方式 align items 设置
  • flutter 组件 Stepper,Step,Padding,Align,Center,FittedBox,AspectRatio,ConstrainedBox

    1 Stepper Step Stepper Key key required this steps step类型的子集 this physics this type StepperType vertical 方向 this current
  • java如何将word转化为pdf文件

    相信大家对于java应该都不陌生了 毕竟作为一款计算机语言它的使用频率还是非常高的 很多朋友知道java能进行程序编写 今天小编就给大家介绍一下如何使用java里的jacob来进行word转成pdf格式文件的具体操作 有需要的朋友赶紧一起来
  • vue打包elementUI的时候,小图标变成小方框

    在vue的build文件夹找到utils js文件 然后在下面这个位置添加 publicPath function generateLoaders loader loaderOptions const loaders options use
  • 基于SpringBoot+Vue实现的前后端分离的外卖点餐系统源代码+数据库

    该项目是一个前后端分离的外卖点餐系统 项目后端采用SpringBoot开发 完整代码下载地址 基于SpringBoot Vue实现的前后端分离的外卖点餐系统源代码 数据库 功能模块 基础数据模块 分类管理 员工管理 套餐管理 点餐业务模块
  • 华为机考108题(c++)(70-80)

    HJ70 矩阵乘法计算量估算 描述 矩阵乘法的运算量与矩阵乘法的顺序强相关 例如 A是一个50 10的矩阵 B是10 20的矩阵 C是20 5的矩阵 计算A B C有两种顺序 AB C 或者 A BC 前者需要计算15000次乘法 后者只需
  • activiti-5 核心之CommandContext 转

    众所周知 从以前的jbpm到现今的activiti 流程引擎的内部执行模式是command模式 不管是启动流程 还是推动流程等等 都采用了command的execute方法 而command执行依赖于CommandContext 直译就是c