關於filter/springinterceptor/aop的加載順序

背景

關於filter/springinterceptor/aop的加載順序。filter指繼承javax.servlet.Filter的;springinterceptor是spring裏的攔截器,實現HandlerInterceptor的;aop是指@Aspect註解的類

這三種都可以攔截對controller方法進行攔截。那攔截順序是怎麼樣的?

結論

順序是分級的,filter/springinterceptor/aop三級。只要是filter就比springinterceptor先,只要是springinterceptor就比aop先。

  • filter和aop的內部順序規則是一致的
  1. 如果不用@Order註解,相當於用 @Order(Integer.MAX_VALUE)
  2. 順序按照@Order的值從小到大,如果值相同,就按照 “在項目中的先後順序規則”
在項目中的先後順序規則:
即出現在本項目中的位置,例如在IDEA中處於上面的就比下面的優先。例如filter/aop包名靠前,按包名順序,假如同包名則按照文件名的順序(不是按bean名字的順序)。外部JAR包排在本項目之後,所以如果JAR包中存在@Order與本項目的@Order相同的時候,本項目排在上面會比較優先。

此規則的例子看附錄
  • springinterceptor的順序
    這個順序比較特別,它不是通過@Order來決定的,它要有個配置類,配置類裏的註冊順序就是順序
@Configuration
public class SpringInterceptorConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SpringInterceptor3()).addPathPatterns("/**");
        registry.addInterceptor(new SpringInterceptor2()).addPathPatterns("/**");
        registry.addInterceptor(new SpringInterceptor()).addPathPatterns("/**");
    }

}

如果JAR包中的springinterceptor和本項目的springinterceptor也一起被掃描,這個順序比較複雜。可以看實際的附錄中的例子。

最佳實踐

通常filter/springinterceptor/aop的執行順序,不會引起大問題,但如果是順序敏感,就必須確保它在最前面
(比如有個filter需要設置請求ID到ThreadLocal(MDC)中,如果它不是最前,其他filter若打印日誌就不能從中獲取到這個變量)

  • 對順序敏感需要排在最前的,要設置 @Order(Integer.MIN_VALUE)
  • 保證一個項目只有一個 @Order(Integer.MIN_VALUE)
  • 保證@Order的值不一樣,比如值都按照 @Order(Integer.MIN_VALUE)、0、10、20、30…這樣子設置

補充問題

1、怎麼證明如果不用@Order註解,相當於用 @Order(Integer.MAX_VALUE)

結論是實際測試出來的,同學們更應該去查源碼,這裏爲了圖省事直接做實驗觀察

可以這麼證明弄兩個filter(A和B),一個用@Order(Integer.MAX_VALUE)另一個不寫。

  1. 看順序,再反過來,看到結果是一樣的,說明兩者是相同的,但需要進一步
  2. 假如順序是AB,且B上的註解是@Order(Integer.MAX_VALUE),A上無註解,此時順序是AB,那我把B上的改成@Order(Integer.MAX_VALUE-1),則打印出BA
    經過這兩個步驟,證明,不寫註解那就是@Order(Integer.MAX_VALUE)

附錄

  1. 以下是JAR包中的filter/springinterceptor/aop也被掃描,和本項目中的一起排順序。最終打印出攔截的結果是

備註:打印出host的是宿主項目,打印出SUB的是被引入的JAR包,其中本項目和JAR包的filter3/2/1以及AOP aspect3/2/1,都配成@Order(0)/10/20,

host Filter3 begin
SUB Filter3 begin
host Filter2 begin
SUB Filter2 begin
host Filter begin
SUB Filter begin
host springinterceptor3: preHandle
host springinterceptor2: preHandle
host springinterceptor: preHandle
SUB springinterceptor3: preHandle
SUB springinterceptor2: preHandle
SUB springinterceptor: preHandle
----- host AOP aspect3 ---- begin
----- SUB AOP aspect3 ---- begin
----- host AOP aspect2 ---- begin
----- SUB AOP aspect2 ---- begin
----- host AOP aspect ---- begin
----- SUB AOP aspect ---- begin
----- SUB AOP aspect ---- end
----- host AOP aspect ---- end
----- SUB AOP aspect2 ---- end
----- host AOP aspect2 ---- end
----- SUB AOP aspect3 ---- end
----- host AOP aspect3 ---- end
SUB springinterceptor: postHandle
SUB springinterceptor2: postHandle
SUB springinterceptor3: postHandle
host springinterceptor: postHandle
host springinterceptor2: postHandle
host springinterceptor3: postHandle
SUB springinterceptor: afterCompletion
SUB springinterceptor2: afterCompletion
SUB springinterceptor3: afterCompletion
host springinterceptor: afterCompletion
host springinterceptor2: afterCompletion
host springinterceptor3: afterCompletion
SUB Filter end
host Filter end
SUB Filter2 end
host Filter2 end
SUB Filter3 end
host Filter3 end

可以看到結論是:filter第一級最優先,springinterceptor第二級,aop第三極。在filter內部,並非本項目的filter就比JAR包中的優先,是平等地要看@Order的值,值相同的再看 “在項目中的先後順序規則”;

springinterceptor的內部規則比較複雜,由於有兩個配置類將對應的攔截器註冊,所以順序是等host的全部完畢再打印JAR包裏的springinterceptor。

aop的內部規則和filter完全一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章