关于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完全一样。

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值