目录
2、BeanFactoryAware(或者ApplicationContextAware)
之前分析了整个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方法就可以获取到代理对象了。