关于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
    评论
AOPAspect Oriented Programming)是一种编程思想,可以在不修改源代码的情况下,通过切面(Aspect)的方式来实现对代码的横向切割,例如拦截方法的调用。在拦截 Service 的方法时,你可以使用 AOP 来实现以下功能: 1. 日志记录:通过在 Service 方法调用前后插入切面,可以记录方法的输入参数、返回值等信息,用于调试和监控。 2. 权限验证:通过拦截 Service 的方法调用,在方法执行前进行权限验证,确保只有具备相应权限的用户可以访问该方法。 3. 缓存管理:通过拦截 Service 的方法调用,在方法执行前检查缓存中是否存在相应的结果,若存在则直接返回缓存数据,减少数据库或其他资源的访问频率。 4. 事务管理:通过拦截 Service 的方法调用,在方法执行前后开启和提交/回滚事务,确保数据的一致性和完整性。 具体实现 AOP 拦截 Service 的方法,你可以使用 Spring AOP 框架。在 Spring 中,你可以通过配置切面和切点来实现对 Service 方法的拦截。可以使用 XML 配置文件或者基于注解的方式来定义切面和切点,并指定要执行的通知(advice)类型,如前置通知、后置通知、环绕通知等。 例如,你可以通过以下步骤来实现 AOP 拦截 Service 方法: 1. 定义切面:创建一个切面类,其中包含要执行的通知方法。 2. 定义切点:在切面类中定义一个切点,指定要拦截的 Service 方法。 3. 配置切面:在 Spring 配置文件中配置切面和切点的关系。 4. 启用 AOP:在 Spring 配置文件中启用 AOP。 具体的代码示例和配置方式可以根据你使用的技术栈和框架来进行调整。希望这些信息对你有帮助!如果你有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值