糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > java 注入 循环_spring依赖注入——循环依赖

java 注入 循环_spring依赖注入——循环依赖

时间:2023-08-10 14:53:23

相关推荐

java  注入 循环_spring依赖注入——循环依赖

上一篇博客简单地分析了下依赖注入。但是对于依赖注入的很多细节,都没有深入的分析。这一篇博客会继续分析spring的依赖注入。这篇博客会解决分析getBean缓存时候遗留下来的循环依赖问题。

循环依赖分析

首先明确下,只有单例情况下,spring才会试着去解决循环依赖问题,多例是不会去解决循环依赖的。这个也好理解,如果是多例的话,比如a -> b 并且 b -> a 那么,当A a=new A(); 之后要注入b,b却是多例的,那么究竟该注入哪个B是不确定的。如下图:

接下来我们分析,为啥会有循环依赖的问题。

先来分析没有循环依赖的问题publicstaticclassA{

privateBb;//省略get和set方法}publicstaticclassB{

}

这个时候,如果spring先初始化A,然后会发现A依赖于B,然后就会初始化B,最后注入到A里。

整个流程用代码表示大概如下所示:Aa=创建A

Bb=创建B

----->创建A子流程a.setB(b);

但是假设B也依赖了A呢?即publicstaticclassB{

privateAa;

}

那样依赖注入过程就会变成(简单示例)Aa=创建A

Bb=创建B

---->创建B子流程b.setA(????);//这个时候A还没创建完成呢a.setB(b);

那么如何解决呢?很简单,把那个还没创建完的A(只是new了,但是没有进行依赖注入的A)set到B里就好了。

弄清了这个流程之后,我们再来分析spring是如何进行依赖注入的。

spring对引用类型的注入

这里我先从spring对引用属性的注入开始。

即ref的注入privateObjectresolveReference(ObjectargName,RuntimeBeanReferenceref){try{StringrefName=ref.getBeanName();

refName=String.valueOf(doEvaluate(refName));if(ref.isToParent()){if(this.beanFactory.getParentBeanFactory()==null){thrownewBeanCreationException(this.beanDefinition.getResourceDescription(),this.beanName,"Can'tresolvereferencetobean'"+refName+"'inparentfactory:noparentfactoryavailable");

}returnthis.beanFactory.getParentBeanFactory().getBean(refName);

}else{Objectbean=this.beanFactory.getBean(refName);this.beanFactory.registerDependentBean(refName,this.beanName);returnbean;

}

}catch(BeansExceptionex){thrownewBeanCreationException(this.beanDefinition.getResourceDescription(),this.beanName,"Cannotresolvereferencetobean'"+ref.getBeanName()+"'whilesetting"+argName,ex);

}

}

实现很简单,就是从beanFactory里获取要依赖的对象

我们再来回顾下流程

问题是,当走到6时候,似乎又会回到1,这样不就死循环了么?

重点就是,第六步的获取A,我们回到doGetBean方法中。

getSingleton 方法protectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference){//已创建的对象里面找下

ObjectsingletonObject=this.singletonObjects.get(beanName);//没找到,并且当前类正在被创建

if(singletonObject==null&&isSingletonCurrentlyInCreation(beanName)){synchronized(this.singletonObjects){

singletonObject=this.earlySingletonObjects.get(beanName);if(singletonObject==null&&allowEarlyReference){

ObjectFactory>singletonFactory=this.singletonFactories.get(beanName);if(singletonFactory!=null){

singletonObject=singletonFactory.getObject();this.earlySingletonObjects.put(beanName,singletonObject);this.singletonFactories.remove(beanName);

}

}

}

}return(singletonObject!=NULL_OBJECT?singletonObject:null);

}

我们在分析初始化bean的缓存部分时,曾分析过这几个缓存。当时其实只知道了singletonObjects是存储了已经创建了的对象。

现在让我们回头再看看这些缓存。

首先看看singletonFactories赋值的地方。

doCreateBean//Eagerlycachesingletonstobeabletoresolvecircularreferences//evenwhentriggeredbylifecycleinterfaceslikeBeanFactoryAware.booleanearlySingletonExposure=(mbd.isSingleton()&&this.allowCircularReferences&&

isSingletonCurrentlyInCreation(beanName));if(earlySingletonExposure){if(logger.isDebugEnabled()){

logger.debug("Eagerlycachingbean'"+beanName+"'toallowforresolvingpotentialcircularreferences");

}

addSingletonFactory(beanName,newObjectFactory(){@Override

publicObjectgetObject()throwsBeansException{//默认实现返回bean

returngetEarlyBeanReference(beanName,mbd,bean);

}

});

}

在创建bean时候,有这样一段代码,当需要进行提前暴露时候(当前创建对象单例 + 允许循环引用 + 当前类正在被创建)会调用addSingletonFactory方法protectedvoidaddSingletonFactory(StringbeanName,ObjectFactory>singletonFactory){

Assert.notNull(singletonFactory,"Singletonfactorymustnotbenull");synchronized(this.singletonObjects){if(!this.singletonObjects.containsKey(beanName)){this.singletonFactories.put(beanName,singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);

}

}

}

这里就碰见了我们要分析的singletonFactories,它存储了beanName -> 此处的匿名内部类singletonFactory。

singletonFactory

我们再回到getSingleton方法,以及之前绘制的图ObjectFactory>singletonFactory=this.singletonFactories.get(beanName);if(singletonFactory!=null){

singletonObject=singletonFactory.getObject();this.earlySingletonObjects.put(beanName,singletonObject);this.singletonFactories.remove(beanName);

}

逻辑很简单

三级缓存

我们经常听说spring通过三级缓存解决了循环依赖,其实三级缓存非常简单。就是指我们分析过的Map singletonObjects

Map> singletonFactories

Map earlySingletonObjects

这里分别举这样三个例子。

A 依赖 B(B不依赖A)

一级缓存

A 依赖 B && B依赖A

三级缓存

A依赖B && B依赖A + B依赖C && C 依赖 A

作者:端吉

链接:/p/10f94b776e55

如果觉得《java 注入 循环_spring依赖注入——循环依赖》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。