首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring MVC 註解風格下攔截器配置完全指南:DefaultAnnotationHandlerMapping 與 AnnotationMethodHandlerAdapter 實戰

     編輯:Java 相關知識

背景:官方文檔只講 XML 風格,註解風格怎麼配攔截器?

Spring 2.5+ 推薦註解驅動開發,核心兩大 Handler:

  • `DefaultAnnotationHandlerMapping`:基於 `@RequestMapping` 映射 URL 到 Controller。
  • `AnnotationMethodHandlerAdapter`:調用 Controller 具體方法,處理參數綁定、返回值解析。

兩者攔截器配置方式**完全不同**,且後者**原生不支持攔截器**,需變通。

方案一:DefaultAnnotationHandlerMapping 內置攔截器支持 (推薦)

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
  <property name="interceptors">
    <list>
      <bean class="com.example.AuthInterceptor"/>
      <bean class="com.example.LoggingInterceptor"/>
    </list>
  </property>
</bean>

攔截器實現

public class AuthInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // handler 為 Controller 類 (DefaultAnnotationHandlerMapping 模式)
        String className = handler.getClass().getName();
        if (needAuth(className) && !isLoggedIn(request)) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return false; // 阻斷請求
        }
        return true; // 放行
    }
}

優點:標準 Spring MVC 攔截器鏈,支持 `preHandle`/`postHandle`/`afterCompletion` 完整生命週期,可訪問 Handler 類信息。

方案二:AnnotationMethodHandlerAdapter 變通 —— customArgumentResolver 偽裝攔截器

痛點:`AnnotationMethodHandlerAdapter` 無 `interceptors` 屬性。GAE 等環境禁用 `DefaultAnnotationHandlerMapping` (依賴 `BeanUtils.findEditorByConvention` → `ClassLoader.getSystemClassLoader` 被禁止) 時,被迫用此方案。

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="customArgumentResolver">
    <bean class="com.example.AuthResolver"/>
  </property>
</bean>

Resolver 實現

public class AuthResolver implements WebArgumentResolver {
    @Override
    public Object resolveArgument(MethodParameter param, NativeWebRequest request) {
        // 1. 獲取 Controller 類名
        String className = param.getMethod().getDeclaringClass().getName();

        // 2. 從 NativeWebRequest 取原生 Request/Response
        HttpServletRequest req = (HttpServletRequest) request.getNativeRequest();
        HttpServletResponse resp = (HttpServletResponse) request.getNativeResponse();

        // 3. 驗證邏輯
        if (needAuth(className) && !isLoggedIn(req)) {
            if (!resp.isCommitted()) { // 關鍵:避免重複提交錯誤
                resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            }
            return UNRESOLVED; // 表示不處理該參數,流程終止
        }
        return UNRESOLVED; // 正常放行,讓後續 Resolver/默認解析器處理參數
    }
}

方案二缺陷與規避

缺陷影響規避措施
每方法參數調用一次 3 參數方法 → 執行 3 次驗證 靜態 `ThreadLocal` 緩存請求級驗證結果,首次計算後復用
非標準攔截點 無 `postHandle`/`afterCompletion`,無法做響應後處理 關鍵邏輯前置;響應後處理改用 `Filter` 或 `ResponseBodyAdvice` (Spring 4.1+)
需手動判斷 `resp.isCommitted()` 避免 `IllegalStateException: Response already committed` 務必加守衛,見代碼

環境選型決策樹

  1. **標準 Servlet 容器 (Tomcat/Jetty/WebLogic...)** → **方案一**,原生、完整、性能最優。
  2. **Google App Engine (GAE) / 受限 ClassLoader 環境** → **方案二** (或升級 Spring 3.0+ 使用 `RequestMappingHandlerMapping`/`RequestMappingHandlerAdapter` 替代舊類)。
  3. **Spring 3.1+** → 棄用上述兩類,改用 `RequestMappingHandlerMapping` (支持 `interceptors`) + `RequestMappingHandlerAdapter` (支持 `argumentResolvers`),架構更清晰。

版本說明

  • 文中方案基於 **Spring 2.5.x**。
  • GAE 版本 **1.2.5** 環境驗證。
  • Spring 3.0+ 引入 `mvc:annotation-driven` 自動註冊新版 Handler,配置更簡潔:
<mvc:annotation-driven>
  <mvc:interceptors>
    <bean class="com.example.AuthInterceptor"/>
  </mvc:interceptors>
</mvc:annotation-driven>

結語

Spring MVC 註解風格下,**`DefaultAnnotationHandlerMapping` 是攔截器的正統載體**;`AnnotationMethodHandlerAdapter` 的 `customArgumentResolver` 僅作受限環境下的權宜之計。現代項目 (Spring 3.1+) 請直接遷移至 `mvc:annotation-driven` + `RequestMappingHandlerMapping`,享受原生攔截器支持與更強的擴展性。理解兩代 Handler 架構差異,是排查遺留系統攔截器失效、參數解析異常的關鍵鑰匙。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved