SpringAop源码(七)- 嵌套调用问题分析与解决

目录

一、本类嵌套Aop问题分析

二、本类嵌套Aop问题解决

1、依赖注入自己

2、BeanFactoryAware(或者ApplicationContextAware)

3、exposeProxy设置为true


    之前分析了整个Aop的实现原理和流程。Spring框架的Transactional,Async等都是基于Spring Aop进行实现的。那么很多时候我们在同一个Bean中,想通A方法调用B方法的时候也被Aop给切中,执行同样的增强逻辑。但是结果是没有被增强。

一、本类嵌套Aop问题分析

    问题:这是一个计算方法耗时的Aop注解,当前其他类调用aMethod的时候,会被执行增强,但是内部调用了bMethod再不会执行增强。

    之前分析过,Spring Aop的实现是基于BeanPostProcess的postProcessAfterInitialization方法,在每个getBean时候,根据原对象(TargetSource)获取一个代理对象,返回给BeanFactory。那么当方法执行的时候,则会先执行invoke或者intercept方法。其真正调用Bean的本方法(连接点)是:

AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);

进入2、的调用实现:

所以使用反射去调用A方法的时候,内部当在调用B方法的时候是不能感知到其他切面的存在的。所以如果想在这里使用代理的话,则需要这个地方拿到的依然是代理对象,代理对象已经存储在BeanFactory中了。

二、本类嵌套Aop问题解决

1、依赖注入自己

    在自己类中注入自己,那么依赖注入的Bean是从BeanFactory容器中获取的代理对象,调用方法时就会再次执行代理方法invoke或者intercept,所以会被增强。

2、BeanFactoryAware(或者ApplicationContextAware)

    上面是在Bean中依赖注入自己,还有一种变相的方法就是从BeanFactory中或者ApplicationContext中调用getBean方法获取代理对象。本质上和第一种是一样的。

3、exposeProxy设置为true

    启动Spring Aop的方式有两种,都可以配置exposeProxy

@EnableAspectJAutoProxy(proxyTargetClass = false, exposeProxy = true)

或者

<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true" />

那么设置之后,最后会在每一个bean创建代理时放入AdvisedSupport advised中的exposeProxy在方法调用(invoke)时使用。

所以当我们执行的时候,当前的代理对象被放在了AopContext中,在方法执行完的finally中再去清除,看看AopContext的实现,很简单就是使用ThreadLocal<代理对象> 的set和remove方法。

public final class AopContext {
    private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");

    private AopContext() {
    }
    
    public static Object currentProxy() throws IllegalStateException {
        Object proxy = currentProxy.get();
        if (proxy == null) {
            throw new IllegalStateException(
                    "Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
        }
        return proxy;
    }
    
    @Nullable
    static Object setCurrentProxy(@Nullable Object proxy) {
        Object old = currentProxy.get();
        if (proxy != null) {
            currentProxy.set(proxy);
        }
        else {
            currentProxy.remove();
        }
        return old;
    }
}

    所以在方法执行的时候,只要调用AopContext的currentProxy方法就可以获取到代理对象了。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值