activiti-5.1核心之CommandContext
来源:互联网 发布:chrome 64 知乎 编辑:程序博客网 时间:2024/06/06 02:00
众所周知,从以前的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);
}
我得说,这一坨东西看上去真丑陋,不过考虑到这块估计也没什么扩展和改动了,就这样吧。
- activiti-5.1核心之CommandContext
- Activiti核心架构之职责链与命令模式
- activiti核心引擎
- Activiti 核心API 简介
- activiti 核心类说明
- Activiti核心API
- activiti 核心api
- Activiti工作流(3):activiti核心API
- 【Activiti笔记】工作流-Activiti核心API介绍
- Activiti工作流引擎核心API
- activiti 数据库核心关系表
- 3.activiti工作流-核心API
- Java Activiti(5)--核心API
- Activiti之流程通过、驳回、会签、转办、中止、挂起等核心操作封装(Activiti5.9)
- Activiti之流程通过、驳回、会签、转办、中止、挂起等核心操作封装(Activiti5.9)
- Activiti之流程通过、驳回、会签、转办、中止、挂起等核心操作封装
- Activiti之流程通过、驳回、会签、转办、中止、挂起等核心操作封装(Activiti5.9)
- Activiti之流程通过、驳回、会签、转办、中止、挂起等核心操作封装(Activiti5.9)
- UNIX时间戳计算,转换, select case when用法,sql字符截取
- wireshark expression
- 滚动到页面顶部
- 在 Ubuntu 10.04 上安装 Kscope,meld
- MYSQL使用笔记(1)
- activiti-5.1核心之CommandContext
- 16天记住7000考研词汇1-8天
- linux 安装mysql
- Java IO流 ObjectInputStream类和ObjectOutputStream类
- Objective-C中的委托用法与讲解
- 编译Android 2.3 Gingerbread Source
- 16天记住7000考研单词9-16天
- hg 使用 教程
- 安装MiniGUI全过程