SpringBean缓存了singletonObjects,一级缓存存放了所有创建的单例BeanearlySingletonObjects。实例化完成,但尚未执行属性注入。而初始化的对象singletonFactories,一个提前暴露的单例工厂,从这个工厂得到的对象的三级缓存之间的关系存储在二级缓存中,在于下面的代码spring在对象getBean()的时候,首先从一级缓存中取出,拿到就直接返回,拿不到就去二级缓存拿,能拿就去三级缓存拿ObjectFactory获取不到,获取到就调用getObject创建对象,获取不到就返回null。当对象真正创建好,可以使用的时候,再放入。什么是循环依赖?谷歌上有这样的答案。简单的说,假设A有一个变量B,B有一个变量A,当Spring第一次实例化A对象时,需要在newA()后给A的B属性赋值。这时候需要renewB(),newB()之后需要给A赋值,导致死循环问题,经典的循环依赖就是这样解决的。假设A依赖B,B依赖A,首先A通过getBean调用doCreateBean(Spring通过getBean方法获取bean,不知道源码的可以看前面的文章),之后初始实例化,在属性注入之前输入以下代码//Eagerlycachesingletonstobeabletoresolvecircularreferences//即使被像BeanFactoryAware这样的生命周期接口触发。booleanearlySingletonExposure=(mbd.isSingleton()&&this.allowCircularReferences&&isSingletonCurrentlyInCreation(beanName));如果(earlySingletonExposure){如果(logger.isTraceEnabled()){logger.trace("急切地缓存bean'"+beanName+"'以允许解析潜在的循环引用");}addSingletonFactory(beanName,()->getEarlyBeanReference(beanName,mbd,bean));}复制代码属性注入之前,Spring将Bean打包为工厂,加入到三级缓存中//这里传入的参数也是lambda表达式,()->getEarlyBeanReference(beanName,mbd,bean)protectedvoidaddSingletonFactory(StringbeanName,ObjectFactory>singletonFactory){Assert.notNull(singletonFactory,"单例工厂不能为空");synchronized(this.singletonObjects){if(!this.singletonObjects.containsKey(beanName)){//添加到L3缓存this。singletonFactories.put(beanName,singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}复制代码这里只是添加了一个工厂(通过这个工厂(ObjectFactory)的getObject方法可以获得一个对象),执行工厂的getObject相当于执行了getEarlyBeanReference那么,什么时候调用这个工厂的getObject方法呢?当A开始属性注入,B开始实例化时,也会使用getBean,同样会注入和A一样的属性,当A再次实例化,A再次实例化时,getBean会通过getBean从三级缓存中取出ObjectFactory得到单例。调用getObject会得到A的对象到此为止,循环依赖就解决了吗?确实解决了循环依赖,但是从流程上看,似乎不需要ObjectFactory缓存?好像singletonObjects和earlySingletonObjects已经可以解决依赖问题了?那么三级缓存的作用是什么呢?我们仔细分析一下singletonFactories什么时候会进入getEarlyBeanReferenceprotectedObjectgetEarlyBeanReference(StringbeanName,RootBeanDefinitionmbd,Objectbean){ObjectexposedObject=bean;如果(!mbd.isSynthetic()&&hasInstantiationAwareBeanPostProcessors()){for(BeanorsPostProcessorbpost):{if(bpinstanceofSmartInstantiationAwareBeanPostProcessor){exposedObject=ibp.getEarlyBeanReference(exposedObject,beanName);}}}返回exposedObject;真正实现该方法只有一个后处理器,即通过@EnableAspectJAutoProxy注解引入的AnnotationAwareAspectJAutoProxyCreator。也就是说,如果不考虑AOP,上面的代码等同于:protectedObjectgetEarlyBeanReference(StringbeanName,RootBeanDefinitionmbd,Objectbean){returnexposedObject;}复制代码意味着工厂什么都不做,直接返回实例化阶段创建的对象!那么不考虑AOP,三级缓存有用吗?讲道理,真的没用。结合AOP的循环依赖,我们之前说过,在普通循环依赖的情况下,三级缓存是没有作用的。三级缓存其实和Spring中的AOP有关。我们先看一下getEarlyBeanReference的代码:protectedObjectgetEarlyBeanReference(StringbeanName,RootBeanDefinitionmbd,Objectbean)如果(!mbd.isSynthetic()&&hasInstantiationAwareBeanPostProcessors()){for(BeanPostProcessorbp:getBeanPostProcessors()){if(bpinstanceofSmartInstantiationAwareBeanPostProcessor){SmartInstantiationAwareBeanPostProcessoribp=(SmartInstantiationAwareBeanPostProcessor)bp;exposedObject=ibp.getEarlyBeanReference(exposedObject,beanName);}}}returnexposedObject;}复制代码如果启用AOP,会调用AnnotationAwareAspectJAutoProxyCreator的AbstractAutoProxyCreator父类的getEarlyBeanReference方法,对应源码如下:publicObjectgetEarlyBeanReference(Objectbean,StringbeanName){ObjectcacheKey=getCacheKey(bean.getClass(),beanName);this.earlyProxyReferences.put(cacheKey,bean);//如果需要代理,返回一个一个代理对象,不需要代理,直接返回当前传入的bean对象returnwrapIfNecessary(bean,beanName,cacheKey);}复制代码回到上面的例子,如果我们对A进行AOP代理,那么getEarlyBeanReference就会返回aproxyobjectinsteadofanobjectcreatedintheinstantiationphase意思是A注入到B中将是一个代理对象,而不是A实例化阶段创建的对象。三级缓存有什么意义呢?以上面的A和B为例,其中A被AOP代理。我们先分析一下三级缓存的使用情况。A和B的创建过程假设不使用三级缓存,直接使用二级缓存。也是可以实现的,那么三级缓存和二级缓存存在的意义是什么?以上两个过程唯一的区别就是为A对象创建代理的时机不同。使用三级缓存时,为A创建代理的时机是A需要注入B的时候,如果不使用三级缓存,则在A实例化后,需要创建代理立即获取A并放入二级缓存。对于A和B的整个创建过程,消耗的时间是一样的(所以说普通三级缓存提高效率是错误的)。在上面的例子中,区别在于在哪里创建代理。不使用三级缓存就使用二级缓存,违反了Spring结合AOP和Bean的生命周期的设计!Spring结合AOP和Bean本身的生命周期是通过后处理器AnnotationAwareAspectJAutoProxyCreator来完成的。在这个后处理的postProcessAfterInitialization方法中,AOP代理完成了对初始化的Bean。如果有循环依赖,没办法只能先为Bean创建代理,但如果没有循环依赖,设计是让Bean在生命周期的最后一步完成代理,而不是完成实例化后立即代理。
