问题
我们都知道在spring中,如果两个bean,相互依赖,那么就会出现循环依赖问题,如果spring对这种问题不进行处理的话,那么就会导致创建bean 失败,所以这就是传说中的三级缓存解决循环依赖的问题。
问题一:相互依赖
从上面的流程图中我们就遇到了循环依赖的问题,也就是在创建BService 的时候,依赖了AService,难道我们再次触发创建AService的流程吗,答案是肯定不行,为了解决这个问题,我们就需要知道哪些bean是正在创建中。
在上面流程中,如果我们增加一个集合,用来存放正在创建的bean,同时用一个map来存放,实例化得到的普通对象,理论上这样我们就可以打破中循环依赖,因为我们在创建BService的时候,可以从map中获得Aservice的对象,并且进行赋值,然后完成创建Bean的生命周期。
问题二:代理对象
上面的解决方案在没有AOP的情况下是没有问题的,但是如果我们在初始化后需要AOP,也就说我们AService,在初始化后需要AOP,这个时候我们都知道会产生一个AService的代理对象,并且最终放在单例池中,但是如果按照上面的解决方案,我们赋值给BService的属性是个普通对象,这肯定是不可以的,所以上面的解决方案需要改进。
这里最大的问题就是,我们怎么知道到底是需要赋值普通对象还是代理对象呢?所以在spring 的源码中引入了一个第三级缓存singletonFactories。这个map中的value存放的是一个Lamda表达式,也就是一个段代码逻辑,这个逻辑就是用来判断是否需要AOP的。
首先,singletonFactories中存的是某个beanName对应的ObjectFactory,在bean的生命周期中,生成完原始对象之后,就会构造一个ObjectFactory存入singletonFactories中。这个ObjectFactory是一个函数式接口,所以支持Lambda表达式:() -> getEarlyBeanReference(beanName, mbd, bean)
上面的Lambda表达式就是一个ObjectFactory,执行该Lambda表达式就会去执行getEarlyBeanReference方法,而该方法如下:
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; }
该方法会去执行SmartInstantiationAwareBeanPostProcessor中的getEarlyBeanReference方法,而这个接口下的实现类中只有两个类实现了这个方法,一个是AbstractAutoProxyCreator,一个是InstantiationAwareBeanPostProcessorAdapter,它的实现如下:
// InstantiationAwareBeanPostProcessorAdapter @Override public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException { return bean; }
// AbstractAutoProxyCreator @Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); this.earlyProxyReferences.put(cacheKey, bean); return wrapIfNecessary(bean, beanName, cacheKey); }
在整个Spring中,默认就只有AbstractAutoProxyCreator真正意义上实现了getEarlyBeanReference方法,而该类就是用来进行AOP的。上文提到的AnnotationAwareAspectJAutoProxyCreator的父类就是AbstractAutoProxyCreator。
那么getEarlyBeanReference方法到底在干什么? 首先得到一个cachekey,cachekey就是beanName。 然后把beanName和bean(这是原始对象)存入earlyProxyReferences中 调用wrapIfNecessary进行AOP,得到一个代理对象。
这样我们就很好解决了普通对象还是代理对象的问题了,但是这里仍然存在一个问题,大家思考一下,如果我们此时还有一个CService也依赖了AService。
问题三:多次生成代理对象
为了解决上面抛出来的问题,在spring中引入了二级缓存earlySingletonObjects,也就是把我们生成的无论是代理对象还是普通对象,都缓存起来,这样其他的bean出现依赖的情况,可以直接从这个缓存中获得,不用重新生成一个代理对象,这样就保证了我们AService的唯一性。
至此,通过引入三级缓存解决了,循环依赖的问题:
总结
三级缓存是通用的叫法。 一级缓存为:singletonObjects 二级缓存为:earlySingletonObjects 三级缓存为**:singletonFactories**
先稍微解释一下这三个缓存的作用,后面详细分析:
singletonObjects中缓存的是已经经历了完整生命周期的bean对象。
earlySingletonObjects比singletonObjects多了一个early,表示缓存的是早期的bean对象。早期是什么意思?表示Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。
singletonFactories中缓存的是ObjectFactory,表示对象工厂,表示用来创建早期bean对象的工厂。