问题
什么是责任链模式?
答案
1. 核心概念
责任链模式(Chain of Responsibility Pattern) 是一种行为型设计模式,将请求的发送者和接收者解耦,让多个对象都有机会处理请求。这些对象组成一条链,请求沿着链传递,直到有对象处理它为止。
核心思想:
- 多个处理器按顺序组成链条
- 请求沿着链传递
- 每个处理器决定是否处理请求,以及是否继续传递
典型应用场景:
- Servlet Filter 过滤器链
- Spring 拦截器(Interceptor)
- Netty 的 ChannelPipeline
- 审批流程(员工请假审批)
- 异常处理链
2. 实现原理与代码示例
基础实现:请假审批流程
// 请假申请
class LeaveRequest {
private String name;
private int days;
public LeaveRequest(String name, int days) {
this.name = name;
this.days = days;
}
public String getName() {
return name;
}
public int getDays() {
return days;
}
}
// 抽象处理器
abstract class Approver {
protected Approver nextApprover; // 下一个处理器
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
// 抽象处理方法
public abstract void processRequest(LeaveRequest request);
}
// 具体处理器1:组长(处理 ≤ 1 天)
class TeamLeader extends Approver {
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 1) {
System.out.println("组长批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else if (nextApprover != null) {
System.out.println("组长无权批准,转交上级");
nextApprover.processRequest(request);
}
}
}
// 具体处理器2:经理(处理 ≤ 3 天)
class Manager extends Approver {
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 3) {
System.out.println("经理批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else if (nextApprover != null) {
System.out.println("经理无权批准,转交上级");
nextApprover.processRequest(request);
}
}
}
// 具体处理器3:总监(处理 ≤ 7 天)
class Director extends Approver {
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 7) {
System.out.println("总监批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
} else {
System.out.println("请假天数过长,总监拒绝了请求");
}
}
}
// 使用示例
public class Client {
public static void main(String[] args) {
// 创建责任链
Approver teamLeader = new TeamLeader();
Approver manager = new Manager();
Approver director = new Director();
// 链接责任链
teamLeader.setNextApprover(manager);
manager.setNextApprover(director);
// 发送请求
LeaveRequest request1 = new LeaveRequest("张三", 1);
teamLeader.processRequest(request1);
System.out.println("---");
LeaveRequest request2 = new LeaveRequest("李四", 5);
teamLeader.processRequest(request2);
System.out.println("---");
LeaveRequest request3 = new LeaveRequest("王五", 10);
teamLeader.processRequest(request3);
}
}
输出结果:
组长批准了 张三 的 1 天请假
---
组长无权批准,转交上级
经理无权批准,转交上级
总监批准了 李四 的 5 天请假
---
组长无权批准,转交上级
经理无权批准,转交上级
请假天数过长,总监拒绝了请求
3. 纯责任链 vs 不纯责任链
纯责任链(Pure Chain)
- 请求只能被一个处理器处理
- 处理后不再传递
// 处理后直接返回,不再传递
if (canHandle(request)) {
handle(request);
return; // 终止链
}
nextHandler.handleRequest(request);
不纯责任链(Impure Chain)
- 请求可以被多个处理器处理
- 每个处理器处理后继续传递
// 处理后继续传递
if (canHandle(request)) {
handle(request);
}
if (nextHandler != null) {
nextHandler.handleRequest(request); // 继续传递
}
4. Servlet Filter 过滤器链(不纯责任链)
// Filter 接口
public interface Filter {
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
}
// 具体过滤器1:编码过滤器
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("设置请求编码为 UTF-8");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// 继续传递给下一个过滤器
chain.doFilter(request, response);
System.out.println("编码过滤器处理响应");
}
}
// 具体过滤器2:登录验证过滤器
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
System.out.println("验证用户登录状态");
if (req.getSession().getAttribute("user") == null) {
System.out.println("用户未登录,拒绝访问");
return; // 终止链
}
// 继续传递
chain.doFilter(request, response);
System.out.println("登录过滤器处理响应");
}
}
// FilterChain 简化实现
public class ApplicationFilterChain implements FilterChain {
private List<Filter> filters = new ArrayList<>();
private int pos = 0; // 当前处理位置
public void addFilter(Filter filter) {
filters.add(filter);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if (pos < filters.size()) {
Filter filter = filters.get(pos++);
filter.doFilter(request, response, this);
} else {
// 所有过滤器执行完毕,调用 Servlet
System.out.println("执行目标 Servlet");
}
}
}
执行流程:
设置请求编码为 UTF-8
验证用户登录状态
执行目标 Servlet
登录过滤器处理响应
编码过滤器处理响应
5. Spring 拦截器(HandlerInterceptor)
public interface HandlerInterceptor {
// 前置处理
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler);
// 后置处理
void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView);
// 完成后处理
void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex);
}
// 自定义拦截器
@Component
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("请求路径:" + request.getRequestURI());
return true; // 返回 true 继续执行,false 中断
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
System.out.println("请求完成");
}
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LogInterceptor logInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/static/**");
}
}
6. Netty 的 ChannelPipeline
// Netty 的责任链实现
ChannelPipeline pipeline = channel.pipeline();
// 添加处理器到责任链
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024));
pipeline.addLast("handler", new HttpServerHandler());
// 每个 Handler 处理完后调用 ctx.fireChannelRead(msg) 传递给下一个
public class MyHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// 处理消息
System.out.println("处理消息:" + msg);
// 传递给下一个处理器
ctx.fireChannelRead(msg);
}
}
7. 责任链模式的优化实现
使用建造者模式构建责任链
// 责任链构建器
public class HandlerChainBuilder {
private List<Handler> handlers = new ArrayList<>();
public HandlerChainBuilder addHandler(Handler handler) {
handlers.add(handler);
return this;
}
public HandlerChain build() {
// 链接所有处理器
for (int i = 0; i < handlers.size() - 1; i++) {
handlers.get(i).setNextHandler(handlers.get(i + 1));
}
return new HandlerChain(handlers.get(0));
}
}
// 使用
HandlerChain chain = new HandlerChainBuilder()
.addHandler(new ValidationHandler())
.addHandler(new AuthHandler())
.addHandler(new LogHandler())
.build();
chain.execute(request);
8. 优缺点分析
优点:
- ✅ 降低耦合度(发送者和接收者解耦)
- ✅ 动态组合处理器(灵活配置责任链)
- ✅ 符合单一职责原则(每个处理器专注一个功能)
- ✅ 符合开闭原则(新增处理器无需修改现有代码)
缺点:
- ❌ 性能问题(请求需要遍历整条链)
- ❌ 调试困难(请求的处理路径不明确)
- ❌ 可能请求无法被处理(链末端未处理)
9. 答题总结
简洁回答模板:
“责任链模式将请求发送者和接收者解耦,让多个处理器对象按顺序组成链条,请求沿链传递直到被处理。
核心结构:
- 抽象处理器:定义处理接口,持有下一个处理器的引用
- 具体处理器:实现具体的处理逻辑,决定是否继续传递
- 客户端:构建责任链并发起请求
两种形式:
- 纯责任链:请求只被一个处理器处理后终止
- 不纯责任链:请求可被多个处理器处理(如 Filter)
典型应用:
- Servlet Filter 过滤器链(编码、鉴权、日志)
- Spring 拦截器(preHandle → Controller → postHandle → afterCompletion)
- Netty 的 ChannelPipeline(编解码、业务处理)
优势:降低耦合、动态组合、易于扩展。适用于多个对象都可能处理请求,且处理顺序需要灵活配置的场景。”