文章目录
- 引言
- 责任链模式简介
- 定义与用途
- 实现方式
- 使用场景
- 优势与劣势
- 在Spring框架中的应用
- 日志示例
- 代码地址
引言
在现实生活中,常常会遇到这样的场景:一个请求或命令需要经过多个层级的处理。例如,一个行政审批流程可能需要通过多个部门的审核。在软件开发中,我们可以使用责任链模式来模拟这种层级处理流程。责任链模式允许我们将请求的发送者和接收者解耦,将多个处理对象连成一条链,依次处理请求。
责任链模式简介
定义与用途
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许将请求沿着处理链传递,直到一个对象处理它为止。每个处理对象都包含逻辑来处理请求或将请求传递给链上的下一个对象。
实现方式
实现责任链模式通常包括以下几个关键组件:
- 处理器接口(Handler): 定义了处理请求的接口。
- 具体处理器(Concrete Handlers): 实现处理器接口,并执行具体的处理逻辑或将请求传递给链上的下一个处理器。
- 客户端(Client): 发起请求,并将请求传递给链上的第一个处理器。
使用场景
责任链模式适用于以下场景:
- 当多个对象可以处理一个请求,但具体由哪个对象处理在运行时才确定时。
- 当想在不明确指定接收者的情况下,向多个对象中的一个提交请求时。
- 当处理请求的一组对象应被动态指定时。
例如:
- 审批流程:不同级别的审批请求通过不同级别的管理层进行处理。
- 事件处理系统:例如 GUI 中的事件传递,事件可以由多个对象处理。
- 日志记录:根据消息的严重性级别,决定将其发送到不同的输出目标。
优势与劣势
- 优势
降低耦合度:请求的发送者和接收者之间没有直接的耦合关系。
增强灵活性:可以动态地改变链内的成员或调整其顺序。
易于扩展:可以通过增加新的处理器来扩展。 - 劣势
不能保证请求一定会被接收:所有处理者都可能不处理请求,使其未被处理。
对链中请求处理者的排列顺序和数量敏感。
在Spring框架中的应用
在Spring框架中,责任链模式通常用于处理一系列的处理步骤或中间件。这种模式在Spring的多个组件中得到应用,最典型的是在Spring Security和Spring MVC中。
1. Spring Security中的责任链应用
在Spring Security中,责任链模式体现在过滤器链(Filter Chain)中。
每个请求都会通过一系列的安全过滤器,每个过滤器执行不同的安全检查和任务。这些过滤器包括:
Authentication Filter:负责用户认证。
Authorization Filter:负责检查用户是否有权限访问特定资源。
Exception Translation Filter:负责处理在安全认证过程中抛出的异常。
每个过滤器处理请求后决定是否将请求传递给链中的下一个过滤器,或者是终止请求并返回响应。这正是责任链模式的核心特征。
2. Spring MVC中的责任链应用
在Spring MVC中,拦截器(Interceptors)也是一种责任链模式的体现。
拦截器用于在处理请求前后执行各种任务,比如日志记录、权限检查、事务处理等。你可以定义多个拦截器,并将它们链接在一起,形成一个拦截器链。
每个拦截器决定是否:
在Controller处理请求之前执行某些操作。
在Controller处理完请求后执行某些操作。
3. Spring中的Filter Chain
Spring的另一个责任链应用是Spring Web中的Filter Chain。在Spring Web中,你可以定义多个过滤器来处理Web请求。
每个过滤器执行完任务后,可以决定是否将请求传递给链中的下一个过滤器。
这些过滤器可以处理跨站请求伪造(CSRF)保护、CORS、编码问题等。
日志示例
步骤 1:创建抽象日志类
首先定义了一个 AbstractLogger 抽象类,作为日志处理者的基类。
public abstract class AbstractLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
// 链中的下一个责任元素
protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger){
this.nextLogger = nextLogger;
}
public void logMessage(int level, String message){
if(this.level <= level){
write(message);
}
if(nextLogger !=null){
nextLogger.logMessage(level, message);
}
}
abstract protected void write(String message);
}
这个类定义了日志级别和处理请求的方法。如果此处理者能处理该级别的日志,它将输出日志;否则,它将请求转发给链中的下一个处理者。
步骤 2:创建具体的日志处理类
创建了具体的日志处理者类,扩展了 AbstractLogger。
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("标准控制台::Logger: " + message);
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("错误控制台::Logger: " + message);
}
}
public class FileLogger extends AbstractLogger {
public FileLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("文件::Logger: " + message);
}
}
每个具体的处理者类负责处理特定级别的日志消息。
步骤 3:创建不同类型的日志处理者并形成链
定义了一个客户端类 ChainPatternDemo 来创建日志处理者链并使用该链处理消息。
public class ChainPatternDemo {
private static AbstractLogger getChainOfLoggers(){
AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
// 形成责任链
errorLogger.setNextLogger(fileLogger);
fileLogger.setNextLogger(consoleLogger);
return errorLogger;
}
public static void main(String[] args) {
AbstractLogger loggerChain = getChainOfLoggers();
loggerChain.logMessage(AbstractLogger.INFO,
"这是一条信息级别的消息。");
loggerChain.logMessage(AbstractLogger.DEBUG,
"这是一条调试级别的消息。");
loggerChain.logMessage(AbstractLogger.ERROR,
"这是一条错误级别的消息。");
}
}
在这个客户端中,我们创建了不同级别的日志处理者并连接它们形成一条链。然后,我们发送不同级别的消息给责任链,可以看到消息被相应级别的处理者处理。
这个示例演示了责任链模式在处理具有不同处理级别的请求中的效力。通过改变链的结构或成员,可以灵活地改变请求处理的方式。
代码地址
23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址
https://github.com/RuofeiSun/lf-23Pattern