以下是为你精心撰写的 《Java 责任链模式深度学习指南》,专为 Java 后端开发者打造,内容涵盖:定义、作用、与过滤器/拦截器的深度对比、真实业务场景、手写实现、Spring Filter/AOP 实现、Spring Gateway 实现、避坑指南、最佳实践、面试高频题,所有示例均含中文注释,可直接用于项目重构、权限校验、风控拦截、日志记录、API 网关、审批流等核心场景。
📘 Java 责任链模式深度学习指南
—— 从“多重 if-else”到“流水线式拦截”的架构升级
作者:Java 后端架构实战导师
适用对象:Java 后端开发者(Spring Boot / 微服务 / API 网关 / 风控系统 / 权限系统)
目标:彻底掌握“让多个对象有机会处理请求,形成一条处理链”的核心模式,告别“嵌套 if-else”和“硬编码顺序”
核心原则:“我不是唯一处理者,我只是链上的一环,传下去,或拦住它。”
✅ 一、什么是责任链模式?
📌 定义:
责任链模式(Chain of Responsibility Pattern) 是一种行为型设计模式,它将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。请求沿着一条处理链传递,直到有一个对象处理它为止。
🔍 核心思想:
- 一组处理器(Handler) 组成一条链
- 每个处理器只关心自己是否能处理,不能处理就传递给下一个
- 请求从链头开始,逐级传递,直到被处理或链尾
- 每个处理器可选择:
- ✅ 自己处理并终止链
- ✅ 自己处理并继续传递
- ✅ 不处理,直接传递给下一个
- 客户端不知道由谁处理,只负责发起请求
💡 一句话记忆:
“我要找领导签字,先找组长,他没权限就找主管,主管没权限就找总监——谁有权限谁处理,不关我的事。”
🆚 责任链模式 vs 多重 if-else
| 方式 | 多重 if-else | 责任链模式 |
|---|---|---|
| 结构 | 所有逻辑写在一个地方 | 每个条件独立成一个类 |
| 扩展性 | 新增规则需修改原代码 | 新增处理器只需注册到链中 |
| 可读性 | 嵌套深,难维护 | 结构清晰,职责单一 |
| 顺序控制 | 固定写死 | 可动态调整顺序 |
| 复用性 | 代码复用差 | 处理器可复用在多个链中 |
| 典型场景 | 小型工具类 | 权限、风控、日志、过滤器 |
✅ 经典比喻:
你去银行办业务:
- if-else:柜员问你“是转账?是开户?是挂失?” → 一连串 if 判断
- 责任链:你先找大堂经理 → 他判断“是咨询” → 转给客户经理 → 他判断“是开户” → 转给柜台 → 柜台处理 → 完成
✅ 二、责任链模式有什么作用?(Why Use Chain of Responsibility?)
| 作用 | 说明 |
|---|---|
| ✅ 消除嵌套 if-else | 避免“if (A) { if (B) { if © { … } } }”的地狱结构 |
| ✅ 支持动态扩展 | 新增拦截器/过滤器只需新增类,不改原有代码 |
| ✅ 支持灵活顺序 | 可配置处理器执行顺序,如:日志 → 权限 → 限流 → 业务 |
| ✅ 解耦请求者与处理者 | 客户端无需知道谁处理、怎么处理 |
| ✅ 支持条件终止 | 一个处理器处理完可终止链,避免后续无效处理 |
| ✅ 支持组合处理 | 多个处理器可协同完成复杂逻辑(如:鉴权 + 审计 + 缓存) |
| ✅ 提高可测试性 | 每个处理器可独立单元测试 |
| ✅ 支撑拦截器架构 | Spring Filter、Spring Interceptor、Netty ChannelHandler 都是责任链模式 |
💡 经典名言:
“Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.”
——《Design Patterns: Elements of Reusable Object-Oriented Software》
✅ 三、责任链模式的典型使用场景(Java 后端真实案例)
| 场景 | 说明 | 是否推荐使用责任链模式 |
|---|---|---|
| ✅ API 网关拦截器 | 日志 → 鉴权 → 限流 → 签名验证 → 路由 | ✅ 强烈推荐 |
| ✅ Web 请求过滤器 | Encoding → CORS → XSS 防护 → Session 检查 | ✅ 强烈推荐 |
| ✅ 订单风控系统 | 黑名单 → 频率限制 → IP 地域 → 设备指纹 → 人工审核 | ✅ 强烈推荐 |
| ✅ 审批流程 | 提交 → 部门主管 → 财务 → 总监 → 归档 | ✅ 强烈推荐 |
| ✅ 日志记录 | 记录请求参数 → 记录响应时间 → 记录用户 → 记录IP | ✅ 推荐 |
| ✅ 消息队列消费者 | 消息解码 → 校验格式 → 业务处理 → 重试 → 死信队列 | ✅ 推荐 |
| ✅ Spring Security | 认证 → 授权 → 会话管理 → CSRF 防护 | ✅ 推荐 |
| ✅ 缓存预热 | 检查本地缓存 → 检查 Redis → 查询 DB → 写入缓存 | ✅ 推荐 |
| ✅ 数据校验 | 非空校验 → 格式校验 → 业务规则校验 → 数据库唯一性校验 | ✅ 推荐 |
| ❌ 单一校验 | 只有“用户名非空”一个判断 | ❌ 直接写 if 即可 |
| ❌ 顺序固定、不可变 | 所有请求都必须走 5 个步骤,无选择 | ❌ 用模板方法更清晰 |
| ❌ 必须全部执行 | 每个环节都必须执行,无终止 | ❌ 用装饰器或策略模式 |
✅ 判断标准:
“有一系列处理步骤,它们有先后顺序,但不是每个都必须执行,且可能中途终止?”
→ 是 → 用责任链模式!
✅ 四、责任链模式的三种实现方式详解(含中文注释)
我们从手写经典版到Spring Filter/AOP,再到Spring Gateway,逐步深入。
🔹 1. 手写责任链模式(经典实现)
/**
* 【1】处理器接口:定义处理方法和下一个处理器
*/
interface RequestHandler {
boolean handle(Request request); // 返回 true 表示已处理,终止链;false 表示继续传递
void setNext(RequestHandler next); // 设置下一个处理器
}
/**
* 【2】基础处理器抽象类(可选,简化代码)
*/
abstract class AbstractRequestHandler implements RequestHandler {
protected RequestHandler next;
@Override
public void setNext(RequestHandler next) {
this.next = next;
}
/**
* 模板方法:统一处理逻辑
*/
@Override
public boolean handle(Request request) {
boolean handled = doHandle(request);
if (!handled && next != null) {
return next.handle(request); // 继续传递
}
return handled; // 已处理或链尾
}
/**
* 子类必须实现的具体处理逻辑
*/
protected abstract boolean doHandle(Request request);
}
/**
* 【3】具体处理器1:日志记录
*/
class LoggingHandler extends AbstractRequestHandler {
@Override
protected boolean doHandle(Request request) {
System.out.println("📝 日志:接收到请求,路径:" + request.getPath() + ",参数:" + request.getParams());
// 日志不终止链,继续传递
return false;
}
}
/**
* 【4】具体处理器2:黑名单拦截
*/
class BlacklistHandler extends AbstractRequestHandler {
@Override
protected boolean doHandle(Request request) {
String ip = request.getIp();
if ("192.168.1.100".equals(ip)) {
System.out.println("⛔ 黑名单拦截:IP " + ip + " 被禁止访问");
return true; // ✅ 终止链,不再传递
}
System.out.println("✅ 黑名单检查:IP " + ip + " 通过");
return false; // 继续传递
}
}
/**
* 【5】具体处理器3:权限校验
*/
class AuthHandler extends AbstractRequestHandler {
@Override
protected boolean doHandle(Request request) {
String token = request.getToken();
if (token == null || !token.startsWith("Bearer ")) {
System.out.println("🚫 权限不足:未提供有效 Token");
return true; // ✅ 终止链
}
System.out.println("✅ 权限校验:Token 验证通过");
return false; // 继续传递
}
}
/**
* 【6】具体处理器4:限流检查
*/
class RateLimitHandler extends AbstractRequestHandler {
private int limit = 5; // 每分钟最多5次请求(简化实现)
private int count = 0;
@Override
protected boolean doHandle(Request request) {
count++;
if (count > limit) {
System.out.println("⚡ 限流拦截:请求频率过高,已超过每分钟 " + limit + " 次");
return true; // ✅ 终止链
}
System.out.println("✅ 限流检查:当前请求次数:" + count);
return false; // 继续传递
}
}
/**
* 【7】请求对象(上下文)
*/
class Request {
private String path;
private String ip;
private String token;
private String params;
public Request(String path, String ip, String token, String params) {
this.path = path;
this.ip = ip;
this.token = token;
this.params = params;
}
// getter 方法
public String getPath() { return path; }
public String getIp() { return ip; }
public String getToken() { return token; }
public String getParams() { return params; }
}
/**
* 【8】客户端:构建责任链并触发
*/
public class ChainOfResponsibilityDemo {
public static void main(String[] args) {
// ✅ 构建责任链:顺序很重要!
RequestHandler logging = new LoggingHandler();
RequestHandler blacklist = new BlacklistHandler();
RequestHandler auth = new AuthHandler();
RequestHandler rateLimit = new RateLimitHandler();
// ✅ 设置链路:日志 → 黑名单 → 权限 → 限流
logging.setNext(blacklist);
blacklist.setNext(auth);
auth.setNext(rateLimit);
// ✅ 模拟请求1:正常请求
System.out.println("=== 请求1:合法请求 ===");
Request request1 = new Request("/api/user", "192.168.1.101", "Bearer abc123", "{}");
logging.handle(request1); // 从链头开始
System.out.println("\n=== 请求2:黑名单IP ===");
Request request2 = new Request("/api/user", "192.168.1.100", "Bearer abc123", "{}");
logging.handle(request2); // 在黑名单被拦截
System.out.println("\n=== 请求3:无 Token ===");
Request request3 = new Request("/api/user", "192.168.1.101", null, "{}");
logging.handle(request3); // 在权限校验被拦截
System.out.println("\n=== 请求4:限流触发 ===");
for (int i = 0; i < 6; i++) {
Request request = new Request("/api/user", "192.168.1.101", "Bearer abc123", "{}");
logging.handle(request); // 第6次被限流
}
}
}
✅ 输出结果:
=== 请求1:合法请求 ===
📝 日志:接收到请求,路径:/api/user,参数:{}
✅ 黑名单检查:IP 192.168.1.101 通过
✅ 权限校验:Token 验证通过
✅ 限流检查:当前请求次数:1
=== 请求2:黑名单IP ===
📝 日志:接收到请求,路径:/api/user,参数:{}
⛔ 黑名单拦截:IP 192.168.1.100 被禁止访问
=== 请求3:无 Token ===
📝 日志:接收到请求,路径:/api/user,参数:{}
✅ 黑名单检查:IP 192.168.1.101 通过
🚫 权限不足:未提供有效 Token
=== 请求4:限流触发 ===
📝 日志:接收到请求,路径:/api/user,参数:{}
✅ 黑名单检查:IP 192.168.1.101 通过
✅ 权限校验:Token 验证通过
✅ 限流检查:当前请求次数:2
...(省略)
✅ 限流检查:当前请求次数:5
📝 日志:接收到请求,路径:/api/user,参数:{}
✅ 黑名单检查:IP 192.168.1.101 通过
✅ 权限校验:Token 验证通过
⚡ 限流拦截:请求频率过高,已超过每分钟 5 次
✅ 优点:
- 结构清晰:每个处理器职责单一
- 可扩展:新增拦截器只需新增类
- 可配置:链顺序可动态调整
- 可终止:任意环节可中断请求
- 符合开闭原则
⚠️ 缺点:
- 手动维护链顺序,容易出错
- 没有统一异常处理
- 不支持异步
🔹 2. 责任链模式 + Spring Filter(Web 层实战)
Spring 的
Filter就是责任链模式的完美体现!每个 Filter 是一个处理器。
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 【1】日志过滤器(Filter)
*/
@Component
@WebFilter(urlPatterns = "/*")
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
System.out.println("📝 日志:请求路径:" + req.getRequestURI() + ",IP:" + req.getRemoteAddr());
// ✅ 关键:调用 chain.doFilter() → 传递给下一个 Filter
chain.doFilter(request, response);
System.out.println("✅ 日志:请求处理完成");
}
}
/**
* 【2】黑名单过滤器
*/
@Component
@WebFilter(urlPatterns = "/*")
public class BlacklistFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String ip = req.getRemoteAddr();
if ("192.168.1.100".equals(ip)) {
System.out.println("⛔ 黑名单拦截:IP " + ip + " 被禁止访问");
// ✅ 不调用 chain.doFilter() → 终止链
return;
}
System.out.println("✅ 黑名单检查:IP " + ip + " 通过");
chain.doFilter(request, response); // 继续传递
}
}
/**
* 【3】权限过滤器
*/
@Component
@WebFilter(urlPatterns = "/*")
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String token = req.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
System.out.println("🚫 权限不足:未提供有效 Token");
return; // ✅ 终止链
}
System.out.println("✅ 权限校验:Token 验证通过");
chain.doFilter(request, response); // 继续传递
}
}
/**
* 【4】限流过滤器(简化版)
*/
@Component
@WebFilter(urlPatterns = "/*")
public class RateLimitFilter implements Filter {
private int count = 0;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
count++;
if (count > 5) {
System.out.println("⚡ 限流拦截:请求频率过高");
return; // ✅ 终止链
}
System.out.println("✅ 限流检查:当前请求次数:" + count);
chain.doFilter(request, response);
}
}
✅ Spring Boot 启动类:
@SpringBootApplication
public class FilterChainDemo {
public static void main(String[] args) {
SpringApplication.run(FilterChainDemo.class, args);
}
}
✅ 测试请求:
curl http://localhost:8080/api/user -H "Authorization: Bearer abc123"
✅ 优势:
- Spring 自动注册:
@Component+@WebFilter自动加入过滤链 - 顺序可控:通过
@Order注解指定执行顺序 - 与 Spring 完全集成:可注入
@AutowiredBean - 生产级标准:Spring Security、Spring Cloud Gateway 底层都基于此
✅ 设置顺序:
@Component @WebFilter(urlPatterns = "/*") @Order(1) // 第一个执行 public class LoggingFilter implements Filter { ... } @Component @WebFilter(urlPatterns = "/*") @Order(2) // 第二个执行 public class BlacklistFilter implements Filter { ... }
🔹 3. 责任链模式 + Spring Gateway(微服务网关)
Spring Cloud Gateway 是现代微服务网关的标杆,其底层就是责任链模式 + Reactor 响应式实现!
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
public class LoggingGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(org.springframework.web.server.ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("📝 日志:请求路径:" + exchange.getRequest().getURI());
// ✅ 关键:chain.filter(exchange) → 传递给下一个 Filter
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
System.out.println("✅ 日志:请求处理完成");
}));
}
@Override
public int getOrder() {
return 1; // 执行顺序
}
}
@Component
public class AuthGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
System.out.println("🚫 权限不足:未提供 Token");
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete(); // ✅ 终止链
}
System.out.println("✅ 权限校验:Token 验证通过");
return chain.filter(exchange); // 继续传递
}
@Override
public int getOrder() {
return 2;
}
}
@Component
public class RateLimitGatewayFilter implements GlobalFilter, Ordered {
private static final int LIMIT = 5;
private static int count = 0;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
count++;
if (count > LIMIT) {
System.out.println("⚡ 限流拦截:请求频率过高");
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete(); // ✅ 终止链
}
System.out.println("✅ 限流检查:当前请求次数:" + count);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 3;
}
}
✅ application.yml 配置:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/api/user/**
✅ 优势:
- 响应式非阻塞:基于 Reactor,支持高并发
- 支持复杂路由:可结合 Predicate、Filter、RewritePath
- 企业级网关标准:Netflix Zuul、Kong、Apigee 都是类似架构
- 可插拔:自定义 Filter 可热部署
✅ 五、责任链模式 vs 过滤器模式 vs 拦截器模式 对比
| 模式 | 责任链模式 | 过滤器模式 | 拦截器模式 |
|---|---|---|---|
| 实现方式 | 手动链式传递 | Servlet Filter | Spring Interceptor |
| 作用域 | 任意 Java 对象 | Web 层(Servlet 容器) | Spring MVC 层 |
| 执行时机 | 任意 | 请求进入容器时 | 请求进入 Controller 前 |
| 是否支持异步 | 可支持 | 可支持(AsyncContext) | 可支持(Async) |
| 典型场景 | 风控、审批流 | 日志、安全、编码 | 权限、日志、事务 |
| 是否 Spring 管理 | 否 | 否(但可 @Component) | ✅ 是 |
| 推荐度 | ✅ 通用 | ✅ Web 层 | ✅ Spring 项目 |
✅ 总结:
- 责任链:通用设计模式
- Filter:Web 层实现
- Interceptor:Spring MVC 层实现
→ 三者本质相同,只是作用范围不同
✅ 六、责任链模式的避坑指南(Java 后端高频踩坑)
| 问题 | 原因 | 解决方案 |
|---|---|---|
| ❌ 没有设置 next | 链断裂,请求被丢弃 | ✅ 手动调用 setNext(),或用 Spring 自动装配 |
| ❌ 顺序错误 | 权限校验在日志前,无法记录 | ✅ 用 @Order 或 List<Handler> 按顺序注入 |
| ❌ 忘记调用 chain.doFilter() | 请求被拦截但无响应 | ✅ 每个处理器必须明确决定是否传递 |
| ❌ 异常未处理 | 一个处理器异常,链崩溃 | ✅ 每个 Handler 加 try-catch,或用统一异常处理器 |
| ❌ 用责任链做同步业务 | 如“扣库存”必须同步 | ✅ 用事务或同步调用,责任链只做前置校验 |
| ❌ 处理器太多导致性能差 | 10+ 个处理器逐级调用 | ✅ 用异步、缓存、批量处理优化 |
| ❌ 没有统一终止机制 | 所有处理器都执行 | ✅ 明确设计“是否终止”逻辑 |
✅ 七、学习建议与进阶路径
| 阶段 | 建议 |
|---|---|
| 📚 第一周 | 将你项目中的“登录校验”多层 if-else 重构为责任链(IP → Token → 权限 → 频率) |
| 📚 第二周 | 用 Spring Filter 实现“请求日志 + 黑名单 + 权限校验”三层过滤 |
| 📚 第三周 | 用 Spring Gateway 实现“API 网关”:鉴权 + 限流 + 签名验证 |
| 📚 第四周 | 阅读 Spring Security 源码:FilterChainProxy 如何构建责任链? |
| 📚 面试准备 | 准备回答: |
“你项目中哪里用了责任链模式?”
“Spring Filter 是责任链模式吗?”
“责任链和模板方法区别?”
“如何保证责任链的顺序?” |
✅ 八、责任链模式面试高频题(附答案)
Q1:责任链模式解决了什么问题?
A:解决了“多个对象都有机会处理请求,且顺序可变、可能中途终止”的问题,避免了嵌套 if-else,实现解耦和扩展。
Q2:Spring Filter 是责任链模式吗?
A:是的!
FilterChain就是责任链,每个Filter是一个处理器,chain.doFilter()就是传递请求。
Q3:责任链模式和模板方法模式的区别?
A:
- 模板方法:固定流程,子类实现步骤
- 责任链:动态链,请求逐级传递,可终止
→ 一个是“你必须按我流程走”,一个是“你传给我,我决定接不接”
Q4:如何控制责任链的执行顺序?
A:
- 手写:调用
setNext()时按顺序链接- Spring:使用
@Order注解指定优先级- Spring Gateway:
Ordered接口定义顺序
Q5:责任链模式适合做事务处理吗?
A:不适合!责任链是前置校验,事务应由模板方法或AOP统一管理,责任链中不应有数据库写入。
✅ 九、总结:责任链模式选型决策树
graph TD
A[需要多个处理器顺序处理请求吗?] --> B{是否在 Web 层?}
B -->|是| C{是否是 Spring 项目?}
C -->|是| D[用 @Component + @WebFilter + @Order]
C -->|否| E[用 Filter + FilterChain]
B -->|否| F[用自定义 Handler + setNext() 链式构建]
✅ 最终推荐:
- Spring Web 项目 → ✅ Filter + @Order(最标准)
- Spring Cloud Gateway → ✅ GlobalFilter + Ordered(最现代)
- 非 Web、复杂流程 → ✅ 手写责任链(最灵活)
- 绝对不要:多重 if-else、顺序硬编码、不终止链
✅ 十、结语:真正的高手,不自己处理,只负责传递
你不是在学“责任链模式”,你是在学“如何让系统各模块各司其职,协同工作”。
✅ 当你看到一个请求经过 5 个过滤器,最终被处理,而你只写了 5 个类,每个类只关心自己那一点逻辑时,你已经掌握了架构设计的艺术。
✅ 当你用 Spring Gateway 实现“全球限流 + 多租户鉴权 + 签名验证”,而前端只发一个请求时,你已经是网关架构师了。
不要为了“用模式”而用模式,
要为了“系统可扩展、可维护、可监控”而选择它。
5759

被折叠的 条评论
为什么被折叠?



