责任链模式

一个认证需求的噩梦

我们团队有个 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能设计复杂系统的过滤器链