Activiti命令拦截器和责任链设计模式
使用场景
每个对流程的操作都可以看成一个命令command,Activiti会对每个命令进行拦截处理,Activiti的命令拦截用到了命令模式和责任链模式,
命令模式的本质在于将命令进行封装,发出命令和执行命令分离;
职责链模式只需要将请求放入职责链上,其处理细节和传递都不需要考虑;
执行入口
commandExecutor是命令执行的入口。
在命令来临时,service会调用commandExecutor的execute方法,例如runtimeService。所以commandExecutor是命令执行的第一步。
那么Activiti是什么时候给service注入commandExecutor的呢?
在ProcessEngineConfigurationImpl中init方法中会initServices,其又在初始化的时候注入commandExecutor,源码如下:
public void initServices() {
initService(repositoryService);
initService(runtimeService);
initService(historyService);
initService(identityService);
initService(taskService);
initService(formService);
initService(managementService);
initService(dynamicBpmnService);
}
public void initService(Object service) {
if (service instanceof ServiceImpl) {
((ServiceImpl) service).setCommandExecutor(commandExecutor);//注入了commandExecutor
}
}
命令模式的表现
上面分析了命令执行的第一步,就是调用CommandExecutor.execute
方法,然后我们跟踪去看这个execute方法,在子类CommandExecutorImpl中看到了实际的调用。
protected CommandInterceptor first; //拦截器
@Override
public <T> T execute(CommandConfig config, Command<T> command) {
return first.execute(config, command); //实际调用的是拦截器的execute方法
}
然后我们对比命令模式的几个特性:
- 将命令进行封装——Activiti封装成了Command对象;
- 命令发出者和执行者分离——Activiti将任务最重交给了CommandInterceptor(CommandInvoker)来执行,而不是直接让CommandExecutor执行,就是命令模式解耦的体现。
责任链模式的表现 & 拦截器顺序
在ProcessEngineConfigurationImpl中init方法中会initCommandExecutor,其中指定了第一个拦截器。
public void initCommandExecutor() {
if (commandExecutor == null) {
CommandInterceptor first = initInterceptorChain(commandInterceptors);
//指定first
commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
}
}
对于整个拦截器链的设置在initCommandInterceptors中。
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);//最后的是commanInvoker
}
}
我们再看看默认拦截器的设置,默认拦截器:log->transaction->context。
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));
}
if (transactionContextFactory != null) {
interceptors.add(new TransactionContextInterceptor(transactionContextFactory));
}
return interceptors;
}
我们再看看拦截器里面到底是做了什么,以log拦截器为例。
public <T> T execute(CommandConfig config, Command<T> command) {
if (!log.isDebugEnabled()) {
// do nothing here if we cannot log
return next.execute(config, command);
}
log.debug("\n");
log.debug("--- starting {} ---------", command.getClass().getSimpleName());
try {
return next.execute(config, command);
} finally {
log.debug("--- {} finished ------------", command.getClass().getSimpleName());
log.debug("\n");
}
}
我们需要关注的就是return next.execute(config, command);
这行代码,这也就是这个责任链执行的过程,每次都执行next的execute,直到没有next(commandInvoker)。
在CommandInvoker的execute方法中,最后是执行了传入的command的execute方法,就是具体命令的方法,各种service都是通过这种方式来运行各自具体的命令。
整个拦截器链调用过程如下: