#责任链模式
#一个认证需求的噩梦
我们团队有个 API 网关需要实现认证逻辑:
// 最初的需求
public void handleRequest(HttpRequest request) {
// 1. IP 白名单检查
if (!isIpWhitelisted(request.getIp())) {
return;
}
// 2. Token 验证
if (!isTokenValid(request.getToken())) {
return;
}
// 3. 权限检查
if (!hasPermission(request.getUserId(), request.getPath())) {
return;
}
// 4. 限流检查
if (!checkRateLimit(request.getUserId())) {
return;
}
// 5. 参数校验
if (!validateParams(request)) {
return;
}
// 6. 业务逻辑
doBusiness(request);
}后来需求越来越多,每个检查都改了代码,每个人都往这个方法里加逻辑。半年后,这个方法积累了 2000 行,git blame 完全看不出谁改了什么。
责任链模式解决的就是这个问题:把处理逻辑串联成链,每个处理器只管自己的事情。
#二、责任链核心结构🔴
#2.1 标准写法
// 处理器接口
interface Handler {
void setNext(Handler next);
Handler getNext();
void handle(Request request);
default void executeNext(Request request) {
Handler next = getNext();
if (next != null) {
next.handle(request);
}
}
}
// 抽象基类
abstract class AbstractHandler implements Handler {
private Handler next;
@Override
public void setNext(Handler next) {
this.next = next;
}
@Override
public Handler getNext() {
return next;
}
@Override
public void handle(Request request) {
if (doCheck(request)) {
executeNext(request); // 传递给下一个
}
}
protected abstract boolean doCheck(Request request);
}
// 具体处理器
class IpWhitelistHandler extends AbstractHandler {
@Override
protected boolean doCheck(Request request) {
if (!isIpWhitelisted(request.getIp())) {
System.out.println("IP not whitelisted: " + request.getIp());
return false;
}
return true;
}
}
class TokenAuthHandler extends AbstractHandler {
@Override
protected boolean doCheck(Request request) {
if (!isTokenValid(request.getToken())) {
System.out.println("Token invalid");
return false;
}
return true;
}
}#2.2 链的组装
class HandlerChain {
private Handler head;
private Handler tail;
public void addHandler(Handler handler) {
if (head == null) {
head = handler;
tail = handler;
} else {
tail.setNext(handler);
tail = handler;
}
}
public void handle(Request request) {
if (head != null) {
head.handle(request);
}
}
}
// 组装
HandlerChain chain = new HandlerChain();
chain.addHandler(new IpWhitelistHandler());
chain.addHandler(new TokenAuthHandler());
chain.addHandler(new PermissionHandler());
chain.addHandler(new RateLimitHandler());
chain.addHandler(new ParamValidationHandler());
chain.addHandler(new BusinessHandler()); // 最后一个处理器#三、Spring MVC 拦截器链🟡
public interface HandlerInterceptor {
// 前置处理
default boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return true;
}
// 后置处理
default void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
}
// 完成处理
default void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
}
}
// 认证拦截器
class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String token = request.getHeader("Authorization");
if (!isValid(token)) {
response.setStatus(401);
return false;
}
return true;
}
}
// Spring Boot 配置
@Configuration
class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/api/**");
}
}Spring MVC 的拦截器链执行顺序:
请求 → Interceptor1.preHandle(true) → Interceptor2.preHandle(true)
→ Controller → Interceptor2.postHandle → Interceptor1.postHandle
→ Interceptor2.afterCompletion → Interceptor1.afterCompletion#四、Spring Security 过滤器链🟡
@Configuration
class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.addFilterBefore(new IpWhitelistFilter(),
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JwtAuthFilter(),
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new RateLimitFilter(),
UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.build();
}
}
// 自定义过滤器
class JwtAuthFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
String token = request.getHeader("Authorization");
if (token != null && isValid(token)) {
Authentication auth = new JwtAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response); // 传递给下一个过滤器
}
}Spring Security 的过滤器链:
请求 → SecurityContextPersistenceFilter
→ UsernamePasswordAuthenticationFilter
→ JwtAuthFilter(自定义)
→ RateLimitFilter(自定义)
→ FilterSecurityInterceptor
→ Controller#五、生产避坑🟡
#5.1 断链问题
// ❌ 错误:处理完不断链
class BadHandler extends AbstractHandler {
@Override
protected boolean doCheck(Request request) {
process(request);
return true; // 正确执行了,但不调用 executeNext
}
}
// ✅ 正确:显式传递
class GoodHandler extends AbstractHandler {
@Override
protected boolean doCheck(Request request) {
process(request);
return true;
}
@Override
public void handle(Request request) {
if (doCheck(request)) {
executeNext(request); // 显式调用下一个
}
}
}#5.2 链的顺序
正确顺序:
1. IP 白名单(最快,排除无效请求)
2. 限流(快速失败)
3. Token 认证
4. 权限校验
5. 参数校验
6. 业务处理
错误顺序:
业务处理 → Token 认证(业务都执行完了才认证)【架构权衡】 责任链模式的代价是调试困难(请求通过一串处理器,不知道在哪一步失败了)和性能开销(每个处理器都有调用开销)。适合"横切关注点"(认证、限流、日志)分离到独立处理器。
#六、面试总结
| 级别 | 期望回答 |
|---|---|
| P5 | 能写出责任链基本结构 |
| P6 | 能说出 Spring MVC 拦截器和 Spring Security 过滤器的应用 |
| P7 | 能设计复杂系统的过滤器链 |