Spring的三层缓存,解决循环依赖问题
2019-03-20 17:52
1176 查看
Spring中的BEAN可以通过Setter或者构造器的方式注入属性,那么如果有两个相互引用的类
如
class A{
B b;
...get
...set
},
class B{
A a;
...get
...set
},
基于Spring的单例模式的话,这两个单例对象需要相互引用,那么这个时候Spring又如何适应这种循环依赖呢,平常的直接存BeanFactory中读取出Bean的方法当然不能使用了,那么平时有做算法题习惯的人,就知道我们需要先使用Map进行暂时存储。而Spring也使用类似的方法。
接下来要上Spring源码了
[code] //DefaultSingletonBeanRegistry中 @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); //判断当前Bean是否存在且是正在创建的单例Bean,使用三级缓存 if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) { Map var4 = this.singletonObjects; synchronized(this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); //二级缓存 if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName); //三级缓存 if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
1.singletonObjects
2.earlySingletonObjects
3.singletonFactory
简单来说,使用三级缓存判断是否存在当前Bean,如果存在,则逐层返回,
那么就有两个问题,三级缓存是什么时候设置的,这三种缓存又有什么区别?
接下来看看createBean的方法
[code] protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // 先从factoryBeanInstanceCache缓存中尝试获取 BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } //如果缓存中不存在,则根据bean对应的策略创建新的实例,如:工厂方法、构造器自动注入、简单初始化 if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // 应用MergedBeanDefinitionPostProcessor 后处理器,合并bean的定义信息 // Autowire等注解信息就是在这一步完成预解析,并且将注解需要的信息放入缓存 synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } //catch.. mbd.postProcessed = true; } } // 是否需要提前曝光=单例&允许循环依赖&bean正在创建中 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { //为了避免循环依赖,在bean初始化完成前,就将创建bean实例的ObjectFactory放入工厂缓存(singletonFactories) addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // 对bean属性进行填充,注入bean中的属性,会递归初始化依赖的bean Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); //调用初始化方法,比如init-method、注入Aware对象、应用后处理器 exposedObject = initializeBean(beanName, exposedObject, mbd); } //catch if (earlySingletonExposure) { //从提前曝光的bean缓存中查询bean,目的是验证是否有循环依赖存在 //如果存在循环依赖,也就是说该bean已经被其他bean递归加载过,放入了提早曝光的bean缓存中 Object earlySingletonReference = getSingleton(beanName, false); //只有检测到循环依赖的情况下,earlySingletonReference才不会为null if (earlySingletonReference != null) { //如果exposedObject没有在 initializeBean 初始化方法中改变,也就是没有被增强 if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { //检测依赖 String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } //因为bean创建后,其依赖的bean一定也是已经创建的 //如果actualDependentBeans不为空,则表示依赖的bean并没有被创建完,即存在循环依赖 if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException("..."); } } } } // 根据scope注册bean try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } //catch。。。 return exposedObject; //引用https://blog.csdn.net/finalcola/article/details/81449140
第三层缓存-》保存工厂方法
第二层缓存-》保存未完全装载的方法
第一层-》完全体
那么工厂方法又是什么时候创建的呢?
[code]public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{ /** * 充当了Bean实例的缓存,实现方式和单例注册表相同 */ private final Map singletonCache=new HashMap(); public Object getBean(String name)throws BeansException{ return getBean(name,null,null); } ... public Object getBean(String name,Class requiredType,Object[] args)throws BeansException{ //对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或则做转码) String beanName=transformedBeanName(name); Object bean=null; //手工检测单例注册表 Object sharedInstance=null; //使用了代码锁定同步块,原理和同步方法相似,但是这种写法效率更高 synchronized(this.singletonCache){ sharedInstance=this.singletonCache.get(beanName); } if(sharedInstance!=null){ ... //返回合适的缓存Bean实例 bean=getObjectForSharedInstance(name,sharedInstance); }else{ ... //取得Bean的定义 RootBeanDefinition mergedBeanDefinition=getMergedBeanDefinition(beanName,false); ... //根据Bean定义判断,此判断依据通常来自于组件配置文件的单例属性开关 //<bean id="date" class="java.util.Date" scope="singleton"/> //如果是单例,做如下处理 if(mergedBeanDefinition.isSingleton()){ synchronized(this.singletonCache){ //再次检测单例注册表 sharedInstance=this.singletonCache.get(beanName); if(sharedInstance==null){ ... try { //真正创建Bean实例 sharedInstance=createBean(beanName,mergedBeanDefinition,args); //向单例注册表注册Bean实例 addSingleton(beanName,sharedInstance); }catch (Exception ex) { ... }finally{ ... } } } bean=getObjectForSharedInstance(name,sharedInstance); } //如果是非单例,即prototpye,每次都要新创建一个Bean实例 //<bean id="date" class="java.util.Date" scope="prototype"/> else{ bean=createBean(beanName,mergedBeanDefinition,args); } } ... return bean; } }
相关文章推荐
- Spring中的循环依赖问题介绍及解决方法
- Spring中的循环依赖问题介绍及解决方法
- 解决spring循环依赖的问题:has been injected into other beans
- spring 源码探索--单例bean解决循环依赖问题
- spring多个动态代理导致循环依赖报错问题解决
- Spring源码学习--Bean对象循环依赖问题解决(四)
- 解决spring循环依赖的问题:has been injected into other beans
- Angular4---认证---使用HttpClient拦截器,解决循环依赖引用的问题
- [经验总结]解决Ubuntu系统中deb包循环依赖的问题
- 解决Maven项目相互依赖/循环依赖/双向依赖的问题
- Python循环依赖问题的解决
- 转--解决Spring中singleton的Bean依赖于prototype的Bean的问题
- Spring如何解决循环依赖
- Spring - Bean 循环依赖问题
- Spring的循环依赖问题
- Spring循环依赖问题
- Springboot循环依赖解决办法
- spring bom 解决spring依赖多版本问题
- Spring如何解决循环依赖
- 解决Maven项目相互依赖/循环依赖/双向依赖的问题