责任链模式(Chain of Responsibility Pattern),简而言之,就是把具有能力处理某种任务的类组合成这个链,这个链一般是有头有尾的,在此我们称链中的每一个类为节点,当需要处理的请求到达链头时,就会执行节点的处理逻辑,每个节点的处理情况可分为三种:
- 当前节点处理完并直接返回(一般是到尾节点)
- 当前节点不作任何处理传给下一个节点
- 当前节点进行相关处理后再传给下一个节点
最近在阅读开源工作流项目flowable的源码时发现大量应用了责任链模式,本文先模拟日志级别处理来介绍一个简单的责任链模式,然后再看flowable源码中的实现。
1. 责任链模式之日志级别处理
先以我们比较熟悉的日志系统为例,假如现在我们要实现一个有Debug, Info, Warn, Error四个级别的日志系统,需要满足以下条件:
a. 系统启动时可以配置日志级别,打印日志时可以设置日志的级别。
b. 日志级别从小到大依次为Debug, Info, Warn, Error, 且只有当配置日志级别小于或等于某类日志级别时,才会打印相应级别的日志,否则不打印。
备注: 为了方便判断,我们分别用1,2,3,4来表示这四个日志级别。
用责任链实现的日志系统类图如下:
首先定义一个接口,如下:
public interface Logger {
/**
* 打印日志的方法
* @param message 具体内容
* @param msgLevel 日志级别
* @throws Exception 当打印消息的日志级别不在范围内时抛出异常
*/
void excute(String message, int msgLevel) throws Exception;
/**
* 获取日志类的下一个节点
* @return
*/
Logger getNext();
/**
* 设置日志类的下一个节点,以形成责任链
* @param logger
* @throws Exception
*/
void setNext(Logger logger) throws Exception;
}
然后定义一个实现上面接口的抽象类:
public abstract class AbstractLogger implements Logger{
/**
* 日志类的下一个节点
*/
protected Logger next;
/**
* 系统的日志级别
*/
protected int configLevel;
public AbstractLogger(int configLevel) throws Exception {
if(configLevel < 1 || configLevel > 4){
throw new Exception("Unsupported logger config level, only 1 to 4 is allowed!");
}
this.configLevel = configLevel;
}
@Override
public Logger getNext() {
return next;
}
@Override
public void setNext(Logger logger) throws Exception {
this.next = logger;
}
/**
* 提供给子类用的公共方法
* @param message
*/
protected void print(String message){
System.out.println(message);
}
}
然后是四个级别对应的日志实现类:
首先是责任链中第一个节点:
public class ErrorLogger extends AbstractLogger {
public static final int level = 4;
public ErrorLogger(int configLevel) throws Exception {
super(configLevel);
}
@Override
public void excute(String message, int msgLevel) throws Exception {
if(msgLevel == level){
print("Logger::Error: " + message);
}else if(msgLevel >= configLevel){
next.excute(message, msgLevel);
}
}
}
第二个节点:
public class InfoLogger extends AbstractLogger {
public static final int level = 2;
public InfoLogger(int configLevel) throws Exception {
super(configLevel);
}
@Override
public void excute(String message, int msgLevel) throws Exception {
if(msgLevel == level){
print("Logger::Info: " + message);
}else if(msgLevel >= configLevel){
next.excute(message, msgLevel);
}
}
}
第三个节点:
public class WarnLogger extends AbstractLogger {
public static final int level = 3;
public WarnLogger(int configLevel) throws Exception {
super(configLevel);
}
@Override
public void excute(String message, int msgLevel) throws Exception {
if(msgLevel == level){
print("Logger::Warn: " + message);
}else if(msgLevel >= configLevel){
next.excute(message, msgLevel);
}
}
}
最后一个节点:
public class DebugLogger extends AbstractLogger {
public static final int level = 1;
public DebugLogger(int configLevel) throws Exception {
super(configLevel);
}
@Override
public void excute(String message, int msgLevel) throws Exception {
if(msgLevel == level){
print("Logger::Debug: " + message);
}
}
/**
* Debug为最低的级别,在责任链中没有下一个节点
* @return
*/
@Override
public Logger getNext() {
return null;
}
/**
* 当尝试给Debug日志类设置下一个节点时抛出异常
* @param logger
* @throws Exception
*/
@Override
public void setNext(Logger logger) throws Exception {
throw new Exception("Next Logger in not Allowed in here!");
}
}
测试类的代码如下:
public class ChainPatternDemo {
/**
* 设置的系统的日志级别,组合日志处理责任链,返回责任链的首个节点
* @param level 系统的日志级别
* @return
* @throws Exception
*/
public static Logger initLogConfig(int level) throws Exception {
try{
Logger root = new ErrorLogger(level);
Logger warnLogger = new WarnLogger(level);
Logger infoLogger = new InfoLogger(level);
Logger debugLogger = new DebugLogger(level);
root.setNext(warnLogger);
warnLogger.setNext(infoLogger);
infoLogger.setNext(debugLogger);
return root;
}catch (Exception e){
throw e;
}
}
public static void main(String[] args) {
try{
Logger logger = initLogConfig(4);
logger.excute("error message", 4);
logger.excute("warn message", 3);
logger.excute("info message", 2);
logger.excute("debug message", 1);
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
通过Logger logger = initLogConfig(4)
中的数字设置日志级别,然后尝试打印所有级别的日志, 当设置为1即最低时,输出如下, 打印所有日志,符合预期
Logger::Error: error message
Logger::Warn: warn message
Logger::Info: info message
Logger::Debug: debug message
当设置日志级别为2时,输出如下,只打印info及以上级别的日志,符合预期:
Logger::Error: error message
Logger::Warn: warn message
Logger::Info: info message
当设置日志级别为4即最高时,输出如下,只打印Error级别的日志,符合预期:
Logger::Error: error message
所有的日志处理都会通过定义的责任链进行处理,每个责任链中的节点只有在需要时才进行处理或者传递给下一个节点处理。
2. flowable中的责任链模式
如下,以RuntimeServiceImpl为例, 在flowable源码中很多这样的调用,这就是典型的责任链模式的应用。
此处关键在于实现了ServiceImpl这个类,如下所示,flowable的几大主要类都实现了该接口。
相关的类结构图如下:
ServiceImpl类有CommandExecutor类型的成员变量,而CommandExecutor的实现类又有CommandInterceptor类型的成员变量,实现CommandInterceptor的抽象类中的成员变量next也是一个CommandInterceptor类,通过next既可以实现责任链模式,AbstractCommandInterceptor的如下实现类将作为责任链中的节点。
那么责任链的前后关系又是怎样的呢,这里我们就要查看ProcessEngineConfigurationImpl的源码了,这个类的initInterceptorChain方法即为责任链的初始处理逻辑,如下:
public CommandInterceptor initInterceptorChain(List chain) {
if (chain == null || chain.isEmpty()) {
throw new FlowableException("invalid command interceptor chain configuration: " + chain);
}
for (int i = 0; i < chain.size() - 1; i++) {
chain.get(i).setNext(chain.get(i + 1));
}
return chain.get(0);
}
可以看到责任链的前后关系是按照列表中的顺序的,所以关键点在于传参,找到调用这个方法的地方:
public void initCommandExecutor() {
if (commandExecutor == null) {
CommandInterceptor first = initInterceptorChain(commandInterceptors);
commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
}
}
参数commandInterceptors是ProcessEngineConfigurationImpl类的一个成员变量,所以接下来要看看哪里初始化这个成员变量,如下:
public void initCommandInterceptors() {
if (commandInterceptors == null) {
commandInterceptors = new ArrayList();
if (customPreCommandInterceptors != null) {
commandInterceptors.addAll(customPreCommandInterceptors);
}
commandInterceptors.addAll(getDefaultCommandInterceptors());
if (customPostCommandInterceptors != null) {
commandInterceptors.addAll(customPostCommandInterceptors);
}
commandInterceptors.add(commandInvoker);
}
}
public Collection extends CommandInterceptor> getDefaultCommandInterceptors() {
List interceptors = new ArrayList();
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;
}
先添加自定义前置节点,再添加默认节点(先是LogInterceptor, 然后createTransactionInterceptor(),接着CommandContextInterceptor,还有一个成员变量transactionContextFactory),再添加自定义后置节点,最后还加加上CommandInvoker。所以我们如果没有特殊配置的话这条链依次会有LogInterceptor, TransactionContextInterceptor(和使用环境有关,在Spring下为SpringTransactionInterceptor), CommandContextInterceptor,TransactionContextInterceptor, CommandInvoker这五个节点。通过调试源码可以验证我们的分析,如下:
接着runtimeService也会进行相关初始化,其中责任链结构如下:
查看前四个节点,如下以LogInterceptor为例,肯定会有next.execute(config, command);
, 这也是保证责任链能够往下走的决定因素。
接下来再看看最后一个节点CommandInvoker的源码,关键是执行了command的execute方法,没有next.execute了。
同时可以发现getNext()返回为null, 即获取不到下一个节点,并且在尝试设置下一个节点时会抛出异常,这也正是责任链链尾节点应有的特征。
由此也可以看出所有业务逻辑的处理最终会通过comand.execute来完成,所以接下来就是要搞清楚Command的处理逻辑,具体请待下一篇分析。