過濾器vs攔截器十個致命區別,看懂Spring底層設計才算真懂JavaWeb
在Java Web開發領域,"過濾器(Filter)"和"攔截器(Interceptor)"是兩種常用的請求處理機制,但它們的實現原理和適用場景存在本質差異。本文將從技術規范、設計模式、執行流程、底層實現等多個維度進行深度剖析,結合Servlet 4.0規范和Spring Framework 5.x源碼,揭示二者的技術本質。
一、技術規范與設計哲學
1.1 過濾器的規范基礎
過濾器是Java Servlet規范(JSR 369)定義的標準組件,位于javax.servlet包中。其核心接口Filter定義如下:
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {}
void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
default void destroy() {}
}
設計特點:
? 基于Servlet容器(Tomcat/Jetty)的原生支持
? 采用責任鏈模式(Chain of Responsibility)
? 處理粒度在HTTP請求/響應層面
? 與具體Web框架解耦
1.2 攔截器的框架實現
攔截器是Spring MVC框架的產物,核心接口HandlerInterceptor:
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {}
default void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) {}
default void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler,
Exception ex) {}
}
設計特點:
? 深度集成于Spring上下文
? 采用AOP思想實現
? 處理粒度在Controller方法層面
? 依賴Spring的DispatcherServlet架構
二、執行流程與底層機制
2.1 過濾器執行鏈分析
以Tomcat 9.x為例,過濾器鏈的實現類ApplicationFilterChain維護了一個Filter數組:
final class ApplicationFilterChain implements FilterChain {
private Filter[] filters = new Filter[0];
private int pos = 0;
private int n = 0;
public void doFilter(ServletRequest request, ServletResponse response) {
if (pos < n) {
Filter filter = filters[pos++];
filter.doFilter(request, response, this);
} else {
servlet.service(request, response);
}
}
}
關鍵流程:
- 容器接收到請求后創建FilterChain實例
- 按web.xml配置順序加載匹配的Filter
- 通過遞歸調用實現鏈式執行
- 最終調用目標Servlet的service()方法
2.2 攔截器執行機制
Spring MVC通過HandlerExecutionChain管理攔截器:
public class HandlerExecutionChain {
private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
boolean applyPreHandle(HttpServletRequest request,
HttpServletResponse response) {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
return false;
}
}
return true;
}
}
執行時序:
- DispatcherServlet觸發HandlerMapping
- 創建包含匹配攔截器的HandlerExecutionChain
- 按注冊順序執行preHandle()方法
- Controller方法執行
- 逆序執行postHandle()方法
- 完成視圖渲染后逆序執行afterCompletion()
三、核心技術差異點
3.1 作用域與生命周期
維度 | 過濾器(Filter) | 攔截器(Interceptor) |
初始化時機 | Web應用啟動時 | Spring上下文初始化后 |
作用范圍 | 所有HTTP請求 | Spring管理的Controller請求 |
生命周期管理 | Servlet容器 | Spring Bean容器 |
配置方式 | web.xml/@WebFilter | XML/JavaConfig/注解 |
3.2 執行位置與順序
請求處理流程:
HTTP Request
↓
Tomcat FilterChain
↓
Servlet Container
↓
DispatcherServlet
↓
Spring Interceptor Chain
↓
Controller Method
執行順序示例:
Filter1#doFilter
Filter2#doFilter
Interceptor1#preHandle
Interceptor2#preHandle
Controller#method
Interceptor2#postHandle
Interceptor1#postHandle
Filter2#doFilter (后續處理)
Filter1#doFilter (后續處理)
Interceptor2#afterCompletion
Interceptor1#afterCompletion
3.3 技術實現對比
過濾器實現原理:
? 基于Servlet API的標準實現
? 使用責任鏈模式遞歸調用
? 完全獨立于具體業務框架
? 可修改ServletRequest/ServletResponse
攔截器實現原理:
? 基于Spring AOP的動態代理
? 使用模板方法模式
? 深度集成HandlerAdapter
? 可訪問HandlerMethod參數
四、源碼級技術剖析
4.1 過濾器包裝機制
過濾器可通過Wrapper模式修改請求/響應:
public class LoggingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) {
long start = System.currentTimeMillis();
chain.doFilter(new RequestWrapper(request), new ResponseWrapper(response));
long duration = System.currentTimeMillis() - start;
log.debug("Request processed in {} ms", duration);
}
}
包裝類實現:
class RequestWrapper extends HttpServletRequestWrapper {
private byte[] requestBody;
public RequestWrapper(HttpServletRequest request) {
super(request);
this.requestBody = IOUtils.toByteArray(request.getInputStream());
}
@Override
public ServletInputStream getInputStream() {
return new DelegatingServletInputStream(new ByteArrayInputStream(requestBody));
}
}
4.2 攔截器參數解析
Spring攔截器可訪問HandlerMethod元數據:
public class AuditInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
Method method = hm.getMethod();
Audit audit = method.getAnnotation(Audit.class);
if (audit != null) {
auditService.logRequest(request, audit.value());
}
}
return true;
}
}
五、性能與設計考量
5.1 性能對比維度
指標 | 過濾器 | 攔截器 |
初始化開銷 | 低(容器級) | 中(需要Spring上下文) |
單次執行耗時 | 1-5μs | 5-10μs |
內存占用 | 每個實例獨立 | 共享單例 |
線程安全性 | 要求實現類線程安全 | 默認單例線程安全 |
5.2 設計模式應用
過濾器模式:
? 責任鏈模式:FilterChain維護執行順序
? 裝飾器模式:RequestWrapper/ResponseWrapper
? 模板方法:Filter接口的默認方法
攔截器模式:
? 觀察者模式:HandlerExecutionChain的事件通知
? 策略模式:Interceptor的多個回調方法
? 代理模式:通過AOP實現橫切邏輯
六、應用場景與最佳實踐
6.1 過濾器適用場景
1. 全局字符編碼處理
2. 跨域請求處理(CORS)
3. 請求/響應日志記錄
4. GZIP壓縮處理
5. XSS防御過濾
典型實現:
@WebFilter(urlPatterns = "/*")
public class XssFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) {
chain.doFilter(new XssRequestWrapper((HttpServletRequest) request), response);
}
}
6.2 攔截器適用場景
- 1. 認證與權限驗證
- 2. 請求參數預處理
- 3. 接口響應時間監控
- 4. 業務操作日志記錄
- 5. 全局異常處理
典型實現:
public class AuthInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
String token = request.getHeader("X-Auth-Token");
if (!authService.validateToken(token)) {
response.sendError(401, "Invalid token");
return false;
}
return true;
}
}
七、高級技術集成
7.1 過濾器與Spring集成
通過DelegatingFilterProxy橋接Spring上下文:
@Bean
public FilterRegistrationBean<DelegatingFilterProxy> securityFilter() {
FilterRegistrationBean<DelegatingFilterProxy> reg = new FilterRegistrationBean<>();
reg.setFilter(new DelegatingFilterProxy("springSecurityFilterChain"));
reg.addUrlPatterns("/*");
return reg;
}
7.2 攔截器與AOP整合
結合@Aspect實現細粒度控制:
@Aspect
@Component
public class AuditAspect {
@Around("@annotation(com.example.Auditable)")
public Object auditMethod(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
long duration = System.currentTimeMillis() - start;
auditService.record(pjp.getSignature(), duration);
return result;
}
}
八、總結與選型建議
核心區別總結:
1. 規范層級:過濾器是Servlet標準,攔截器是框架實現
2. 作用范圍:過濾器處理Web容器級請求,攔截器處理Spring MVC級請求
3. 上下文訪問:攔截器可直接訪問Spring Bean,過濾器需要通過代理
4. 執行粒度:過濾器處理HTTP原始數據,攔截器處理業務相關參數
選型建議:
? 需要處理非Spring管理的資源時選擇過濾器
? 需要與Spring上下文深度交互時選擇攔截器
? 性能敏感型操作優先考慮過濾器
? 業務相關橫切關注點使用攔截器
通過深入理解二者的底層機制,開發者可以根據具體需求做出合理的技術選型,構建高效、可維護的Web應用架構。