
责任链模式与过滤器引言责任链模式是一种行为型设计模式它使多个对象都有机会处理请求从而避免请求发送者和接收者之间的耦合。在Java Web开发中过滤器链Filter Chain是责任链模式的经典应用。本文将详细介绍责任链模式的实现以及在Spring MVC、Spring Security中的应用。一、模式结构1.1 基本结构public abstract class Handler { protected Handler nextHandler; public void setNextHandler(Handler handler) { this.nextHandler handler; } public final void handle(Request request) { if (canHandle(request)) { doHandle(request); } if (nextHandler ! null) { nextHandler.handle(request); } } protected abstract boolean canHandle(Request request); protected abstract void doHandle(Request request); } public class ConcreteHandlerA extends Handler { Override protected boolean canHandle(Request request) { return request.getType().equals(A); } Override protected void doHandle(Request request) { System.out.println(HandlerA processing: request); } } public class Client { public static void main(String[] args) { Handler handlerA new ConcreteHandlerA(); Handler handlerB new ConcreteHandlerB(); handlerA.setNextHandler(handlerB); handlerA.handle(new Request(A, Data)); handlerA.handle(new Request(B, Data)); } }二、过滤器接口2.1 Servlet过滤器public interface Filter { default void init(FilterConfig filterConfig) throws ServletException {} void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; default void destroy() {} } public interface FilterChain { void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException; } public class FilterChainImpl implements FilterChain { private final ListFilter filters; private int currentPosition 0; public FilterChainImpl(ListFilter filters) { this.filters filters; } Override public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if (currentPosition filters.size()) { Filter filter filters.get(currentPosition); filter.doFilter(request, response, this); } } }2.2 过滤器实现public class LoggingFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; long startTime System.currentTimeMillis(); try { chain.doFilter(request, response); } finally { long duration System.currentTimeMillis() - startTime; System.out.println(httpRequest.getMethod() httpRequest.getRequestURI() duration ms); } } } public class AuthenticationFilter implements Filter { private final SecurityService securityService; Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; HttpServletResponse httpResponse (HttpServletResponse) response; String token httpRequest.getHeader(Authorization); if (token null || !securityService.validate(token)) { httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return; } chain.doFilter(request, response); } }三、Spring MVC过滤器3.1 CharacterEncodingFilterpublic class CharacterEncodingFilter extends OncePerRequestFilter { private String encoding ISO-8859-1; private boolean forceEncoding false; Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (this.encoding ! null (this.forceEncoding || request.getCharacterEncoding() null)) { request.setCharacterEncoding(this.encoding); response.setCharacterEncoding(this.encoding); } filterChain.doFilter(request, response); } }3.2 Spring表单过滤器Configuration public class WebConfig { Bean public FilterRegistrationBeanCharacterEncodingFilter characterEncodingFilter() { FilterRegistrationBeanCharacterEncodingFilter bean new FilterRegistrationBean(); bean.setFilter(new CharacterEncodingFilter(UTF-8, true)); bean.addUrlPatterns(/*); bean.setOrder(1); return bean; } Bean public FilterRegistrationBeanRequestLoggingFilter loggingFilter() { FilterRegistrationBeanRequestLoggingFilter bean new FilterRegistrationBean(); bean.setFilter(new RequestLoggingFilter()); bean.addUrlPatterns(/api/*); bean.setOrder(2); return bean; } }四、Spring Security过滤器链4.1 SecurityFilterChainConfiguration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(csrf - csrf .ignoringRequestMatchers(/api/**) ) .authorizeHttpRequests(auth - auth .requestMatchers(/public/**).permitAll() .requestMatchers(/admin/**).hasRole(ADMIN) .anyRequest().authenticated() ) .httpBasic(Customizer.withDefaults()) .sessionManagement(session - session .sessionCreationPolicy( SessionCreationPolicy.STATELESS) ) .addFilterBefore(new ApiKeyFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } }4.2 自定义安全过滤器public class ApiKeyFilter extends OncePerRequestFilter { private static final String API_KEY_HEADER X-API-Key; Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String apiKey request.getHeader(API_KEY_HEADER); if (apiKey ! null validateApiKey(apiKey)) { SecurityContext context SecurityContextHolder.createEmptyContext(); context.setAuthentication(new ApiKeyAuthentication(apiKey)); SecurityContextHolder.setContext(context); } filterChain.doFilter(request, response); } private boolean validateApiKey(String apiKey) { return apiKey ! null apiKey.startsWith(API-); } }五、HandlerInterceptor5.1 拦截器接口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 {} }5.2 拦截器实现Component public class AuthenticationInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String path request.getRequestURI(); if (path.startsWith(/public)) { return true; } Authentication auth SecurityContextHolder.getContext().getAuthentication(); if (auth null || !auth.isAuthenticated()) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } return true; } } Component public class PerformanceInterceptor implements HandlerInterceptor { private static final Logger logger LoggerFactory.getLogger(PerformanceInterceptor.class); Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { request.setAttribute(startTime, System.currentTimeMillis()); return true; } Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { long startTime (Long) request.getAttribute(startTime); long duration System.currentTimeMillis() - startTime; logger.debug(Request {} took {}ms, request.getRequestURI(), duration); } }5.3 注册拦截器Configuration public class WebMvcConfig implements WebMvcConfigurer { Autowired private AuthenticationInterceptor authInterceptor; Autowired private PerformanceInterceptor performanceInterceptor; Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor) .addPathPatterns(/**) .excludePathPatterns(/public/**, /login/**); registry.addInterceptor(performanceInterceptor) .addPathPatterns(/api/**); } }六、HandlerInterceptorChain6.1 拦截器链实现public class HandlerInterceptorChain { private final ListHandlerInterceptor interceptors new ArrayList(); private int currentIndex 0; public void addInterceptor(HandlerInterceptor interceptor) { this.interceptors.add(interceptor); } public boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { for (int i 0; i interceptors.size(); i) { HandlerInterceptor interceptor interceptors.get(i); if (!interceptor.preHandle(request, response, handler)) { triggerAfterCompletion(request, response, handler, null); return false; } } return true; } public void applyPostHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { for (int i interceptors.size() - 1; i 0; i--) { interceptors.get(i).postHandle( request, response, handler, modelAndView); } } private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { for (int i 0; i currentIndex; i) { HandlerInterceptor interceptor interceptors.get(i); interceptor.afterCompletion(request, response, handler, ex); } } }七、Spring Cloud Gateway过滤器7.1 全局过滤器Component public class LoggingGlobalFilter implements GlobalFilter { private static final Logger logger LoggerFactory.getLogger(LoggingGlobalFilter.class); Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request exchange.getRequest(); long startTime System.currentTimeMillis(); return chain.filter(exchange) .then(Mono.fromRunnable(() - { long duration System.currentTimeMillis() - startTime; logger.info({} {} - {}ms, request.getMethod(), request.getURI(), duration); })); } }7.2 路由过滤器Configuration public class GatewayFilterConfig { Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route(path_route, r - r .path(/api/**) .filters(f - f .stripPrefix(1) .addRequestHeader(X-Gateway, true) .circuitBreaker(c - c .setName(myCircuitBreaker) .setFallbackUri(forward:/fallback))) .uri(lb://user-service)) .build(); } }八、最佳实践8.1 过滤器顺序Configuration public class FilterOrderConfig { Bean public FilterRegistrationBeanCorsFilter corsFilter() { FilterRegistrationBeanCorsFilter bean new FilterRegistrationBean(); bean.setFilter(new CorsFilter()); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; } Bean public FilterRegistrationBeanSecurityFilter securityFilter() { FilterRegistrationBeanSecurityFilter bean new FilterRegistrationBean(); bean.setFilter(new SecurityFilter()); bean.setOrder(Ordered.HIGHEST_PRECEDENCE 1); return bean; } }8.2 异常处理public class ErrorHandlingFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { chain.doFilter(request, response); } catch (Exception e) { handleException((HttpServletResponse) response, e); } } private void handleException(HttpServletResponse response, Exception e) throws IOException { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setContentType(application/json); response.getWriter().write( {\error\: \ e.getMessage() \}); } }总结责任链模式和过滤器是处理横切关注点的利器在Java Web开发中有广泛应用。Servlet Filter、Spring Security Filter Chain、HandlerInterceptor等都是责任链模式的具体实现。理解这些机制的原理和执行顺序有助于编写高质量的Web应用。