CommandExecutor
命令执行器使用了命令模式和职责链模式。
classDiagram
class CommandInterceptor{
<<Interface>>
execute(CommandConfig cfg, CommandContext ctx, CommandExecutor executor)
setNext(CommandInterceptor arg0)
getNext(): CommandInterceptor
}
class CommandContext {
}
class CommandExecutor {
execute(Command<T> command)
}
class Command {
execute(CommandContext ctx)
}
Command ..> CommandContext : uses
CommandExecutor ..> Command : uses
CommandExecutor o--> CommandInterceptor : owns
CommandInterceptor --> CommandInterceptor : links
Flowable中流程引擎的CommandExecutor实例的拦截器链如下:
相关代码查看
AbstractEngineConfiguration类的initCommandInterceptors()方法。
flowchart TD
LogInterceptor --> CommandContextInterceptor --> TransactionContextInterceptor
--> CommandInvoker
- LogInterceptor 打印日志
- CommandContextInterceptor 负责为要执行的 Command 设置及清理线程本地存储 CommandContext,以及执行CommandContext 的 close 操作
- TransactionContextInterceptor 负责为要执行的 Command 设置及清理本地存储 TransactionContext
- CommandInvoker 开始执行 Command
CommandContext
classDiagram
class CommandContext {
close()
flushSessions()
addCloseListener(CommandContextCloseListener commandContextCloseListener)
}
class TransactionContext {
<<Interface>>
commit()
rollback()
addTransactionListener(TransactionState s, TransactionListener l)
}
class CommandContextCloseListener {
<<Interface>>
closing(CommandContext ctx)
afterSessionFlush(CommandContext ctx)
closed(CommandContext ctx)
closeFailure(CommandContext ctx)
Integer order()
}
class TransactionCommandContextCloseListener {
+TransactionContext transactionContext
}
class StandaloneMybatisTransactionContext {
+CommandContext commandContext
+DbSqlSession dbSqlSession
+Map<TransactionState, List<TransactionListener>> listeners
}
class TransactionListener {
<<Interface>>
execute(CommandContext commandContext): void
}
CommandContext o-- CommandContextCloseListener : has
TransactionCommandContextCloseListener ..|> CommandContextCloseListener : implements
TransactionCommandContextCloseListener o--> TransactionContext : has
StandaloneMybatisTransactionContext ..|> TransactionContext : implements
TransactionContext ..> TransactionListener : uses
CommandContextInterceptor
public class CommandContextInterceptor {
@Override
public <T> T execute(Command<T> command) {
CommandContext commandContext = Context.getCommandContext();
boolean contextReused = false;
/*
* 命令可以执行服用调用,甚至是深度嵌套的服用调用。
* 当开始执行命令时,‘originalContextReusedState’原样存储CommandContext中的‘reused’标记。
* 对于一个嵌套的命令,将会是‘true'。只有在执行根命令上下文时,这个标记才会是’false‘。
* 当执行完嵌套命令时,恢复CommandContext中的`reused`标记,这样允许在CommandInvloker中检测哪一个真正的根命令。
*/
boolean originalContextReusedState = false;
if(commandContext==null || commandContext.getException()!=null){
commandContext = commandContextFactory.createCommandContext();
...
}else{
// 当前存在一个有效的上下文对象,执行命令时将复用这个上下文对象
contextReused = true; // 表明当前上下文对象是被复用的,需要再finally中关闭
originalContextReusedState = commandContext.isReused(); // 存储当前上下的状态
commandContext.setReused(true);
}
try{
Context.setCommandContext(commandContext);
return next.execute(command);
}catch(Exception e){
commandContext.exception(e);
}finally{
try{
if(!contextReused){
commandContext.close(); // 这里很关键
}
commandContext.setResued(originalContxtReusedState); // 恢复执行命令前上下文中的reused状态
}finally{
Context.removeCommandContext();
}
}
if(contextReused && commandContext.getException()!=null){ // 执行当前命令的上下文对象是复用的,而且执行过程中还产生了异常,需要将异常抛出给到上层命令
Throwable exception = commandContext.getException();
commandContext.resetException();
throw new FlowableException("Exception during command execution", exception);
}
return null;
}
}