拦截器有时生效有时不生效

问题

最近在完成一个需求的时候,发现原本配置好的拦截器有时能生效有时又不生效,很奇怪。如果拦截器生效了,那基本可以排除是拦截器本身的问题。

那具体的问题我看了代码之后,也不太清楚,方法确实被调用了,断点调试当中就是没有进入拦截器。

分析

经过排查,我发现这个问题主要是出在调用方式上。

众所周知,AOP是通过代理对象(通常是通过Spring容器管理的)实现的。Spring使用动态代理来在方法调用时插入额外的行为(如日志记录、事务管理等)。当你通过Spring容器调用某个类的方法时,如果该方法被AOP配置了拦截规则(比如我的拦截器, @TraceConfig 注解),Spring会在代理对象上拦截该方法,执行额外的逻辑。

当你在类的内部调用自身的方法时,比如使用 this.method() 方式调用,实际上调用的是该类的原始对象的方法,而不是代理对象的方法。因为AOP代理的前提是通过Spring容器管理的代理对象调用方法,而 this.method() 是直接调用当前类的实例(原始对象)中的方法,不会通过Spring的AOP代理,因此不会触发AOP的拦截器。

当你通过Spring容器调用一个类的方法时,Spring会给这个类生成一个代理对象。这个代理对象负责在方法执行前后插入额外的逻辑。但是,当类内部通过 this 调用方法时,不会经过代理对象,而是直接调用当前实例的原始方法,所以AOP拦截不会生效。

@Component
public class ExampleClass {
    // AOP不会生效
    public void method1() {
        this.method2(); // 不会触发拦截器
    }

    @TraceConfig(configPath = "example")
    public void method2() {
        // 被拦截器拦截
    }
}

解决方法

经过上面的解释,解决方法已经呼之欲出了,那就是保证方法调用来自外部,通过代理对象进行调用。

1.启用exposeProxy

spring:
  aop:
    proxy-target-class: true
    expose-proxy: true

通过这种设置,Spring 会暴露当前的代理对象,使得可以通过 AopContext.currentProxy() 获取。

2.确保在同一线程中调用: 只有在 AOP 代理对象的上下文中,AopContext.currentProxy() 才能被正确调用。如果你在类内部通过 this.method() 调用时,AOP 拦截是不会生效的,因为 this 直接引用的是原始对象,而不是代理对象。

3.正确的调用方式: 通过调用 AopContext.currentProxy() 来获得当前代理对象,然后调用代理对象的方法,而不是直接通过 this 调用。

// 错误调用:this.method() 不会触发 AOP
this.someMethod();

// 正确调用:通过代理对象调用方法
((YourClass) AopContext.currentProxy()).someMethod();

代码示例

import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @TraceConfig
    public void methodA() {
        System.out.println("Executing methodA");

        // 调用代理对象的methodB,而不是直接使用this.methodB()
        ((MyService) AopContext.currentProxy()).methodB();
    }

    @TraceConfig
    public void methodB() {
        System.out.println("Executing methodB");
    }
}

总结

  • 确保 exposeProxy 属性在 Spring 配置中设置为 true
  • 使用 AopContext.currentProxy() 获取代理对象,避免直接通过 this 调用方法。
  • 确保在同一线程中调用代理对象,否则 AopContext.currentProxy() 将无法正常工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值