在上一篇文章中给大家分享了一下循环依赖的问题Spring源码分析之循环依赖,接下来就为大家分析一下三级缓存的存在是如何管理AOP(动态代理)的问题。
//这边不去执行 lambada表达式 只有调用getobject 的时候才会执行
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
在doCreateBean()方法中有一个addSingletonFactory的方法,此方法是通过匿名内部类的方式将lambada表达式作为参数传入进去,这也是我们三级缓存解决循环依赖和AOP代理的关键。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
在这个方法中exposedObject作为我们的当前的一个beanName进行了判断,如果我们不需要AOP生成代理对象增强这个bean,那么会直接return,而当我们的配置文件中存在AOP的配置的时候,会进入if条件中执行代理的方法,例如:
<bean id="logger" class="com.xianjiaochaorou.demo"></bean>
<aop:config>
<aop:aspect id="logger" ref="logger">
<aop:poincut expression="execution(* com.xianjiaochaorou.circle.*.*(..))" id="method"
<aop:before method="recordBefore" pointcut-ref="method"/>
<aop:before method="recordAfter" pointcut-ref="method"/>
</aop:aspect>
</aop:config>
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
执行此方法之后会重新返回一个新的对象(代理对象)存入三级缓存中。
思考:为什么三级缓存可以解决这个问题? 为什么要使用一个匿名内部类的方式去实现?
首先我们应该知道,当一个对象需要被代理的情况下,这个时候在整个的创建过程中是包含两个对象的,一个就是普通的bean对象另一个是代理生成的对象,而在bean对象在创建的过程中默认是单例,所以一个beanName是不可以对应两个对象的,这个时候就需要进行判断,看是否当前的这个benaName是否需要被代理,如果需要则依据上文返回代理之后的对象,如果不需要则直接返回普通的bean对象。 为什么要使用匿名内部的类的方式呢?答案是因为我们并不知道什么时候需要代理对象什么时候需要普通对象,如果出现普通对象和代理对象混合的情况就会出现一个beanName存在两个对象的情况,所以干脆直接使用匿名内部类,也就是每当我们进行返回的时候都默认调用进行判断,这样在需要的时候就可以直接对普通对象进行覆盖,保证全局唯一!!!