背景
关于filter/springinterceptor/aop的加载顺序。filter指继承javax.servlet.Filter的;springinterceptor是spring里的拦截器,实现HandlerInterceptor的;aop是指@Aspect注解的类
这三种都可以拦截对controller方法进行拦截。那拦截顺序是怎么样的?
结论
顺序是分级的,filter/springinterceptor/aop三级。只要是filter就比springinterceptor先,只要是springinterceptor就比aop先。
- filter和aop的内部顺序规则是一致的
- 如果不用@Order注解,相当于用 @Order(Integer.MAX_VALUE)
- 顺序按照@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)另一个不写。
- 看顺序,再反过来,看到结果是一样的,说明两者是相同的,但需要进一步
- 假如顺序是AB,且B上的注解是@Order(Integer.MAX_VALUE),A上无注解,此时顺序是AB,那我把B上的改成@Order(Integer.MAX_VALUE-1),则打印出BA
经过这两个步骤,证明,不写注解那就是@Order(Integer.MAX_VALUE)
附录
- 以下是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完全一样。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/135273.html