spring循环依赖策略解析
循环依赖
所谓循环依赖就是多个bean之间依赖关系形成一个闭环,例如a->b->c->...->a 这种情况,当然,最简单的循环依赖就是2个bean之间互相依赖:a->b(a依赖b), b->a(b依赖a) 。在spring中,如果a->b,那么在创建a的过程中会去创建b,在创建b(或b的依赖)的过程中又发现b->a,这个时候就出现了循环依赖的现象。
循环依赖的解决
spring中的循环依赖只有当
1.bean是单例,
2.通过属性注入的情况
这两个条件满足的情况下是没问题的。但是如果是通过构造器依赖,或者不是单例模式的情况下循环依赖就会抛出异常beancurrentlyincreationexception。下面从代码层面上解析一下为什么。
prototype的循环依赖问题
为什么最先介绍prototype的循环依赖呢,因为可以顺便介绍在spring中创建bean的流程核心流程:在abstractfoctory的dogetbean的方法。这个方法很长,这里只写出核心逻辑,并在注解上注明了个人理解:
protected <t> t dogetbean( final string name, final class<t> requiredtype, final object[] args, boolean typecheckonly) throws beansexception { final string beanname = transformedbeanname(name); object bean; //尝试获取单例对象,因为spring大部分的bean都是单例的,所以这里先尝试能否获取。 registered singletons. object sharedinstance = getsingleton(beanname); //单例存在的情况下,那么beanname返回的肯定是单例类,但是这里还需要判断是不是factorybean if (sharedinstance != null && args == null) { ... //factorybean应该返回getobject()对象 bean = getobjectforbeaninstance(sharedinstance, name, beanname, null); } else { //走到这里,有可能beanname是单例模式,但之前并没有实例化,或者是prototype类型。 //首先判断不是循环依赖,这里的循环依赖指的是prototype类型 if (isprototypecurrentlyincreation(beanname)) { throw new beancurrentlyincreationexception(beanname); } try { final rootbeandefinition mbd = getmergedlocalbeandefinition(beanname); // 如果是单例,则创建单例模式 if (mbd.issingleton()) { // !!!这里是解决单例循环依赖的关键,后面再分析 sharedinstance = getsingleton(beanname, new objectfactory<object>() { @override public object getobject() throws beansexception { try { return createbean(beanname, mbd, args); } catch (beansexception ex) { throw ex; } } }); bean = getobjectforbeaninstance(sharedinstance, name, beanname, mbd); } else if (mbd.isprototype()) { // 原型模式,则创建一个新对象. object prototypeinstance = null; try { /*这里是prototype循环依赖的问题,会记录在map中beanname, 如果在解决当前bean的依赖过程中还依赖当前bean, 则说明了出现了循环依赖 */ beforeprototypecreation(beanname); prototypeinstance = createbean(beanname, mbd, args); } finally { //对应beforeprototypecreation(),从map中移除 afterprototypecreation(beanname); } bean = getobjectforbeaninstance(prototypeinstance, name, beanname, mbd); } ... } } ... return (t) bean; }
可以看出,该流程中就考虑了prototype的循环依赖的问题,只要在创建prototype的bean中出现循环依赖那么就抛出异常。但是在singleton的情况下,则通过另外的方式来解决。
singleton的循环依赖之构造注入
在上面介绍中,出现了一个很关键的地方:
sharedinstance = getsingleton(beanname, new objectfactory<object>() { @override public object getobject() throws beansexception { try { return createbean(beanname, mbd, args); } catch (beansexception ex) { throw ex; } } });
这个getsingleton涉及到了objectfactory这个接口类,这个接口的功能和factorybean类似,但是主要是用来解决循环依赖的。在初始化过程同决定返回的singleton对象是。关于单例的对象的创建,又要介绍一下defaultsingletonbeanregistry这个类,这个类主要用来帮助创建单例模式,其中主要的属性:
/** 缓存创建的单例对象: bean名字 --> bean对象 */ private final map<string, object> singletonobjects = new concurrenthashmap<string, object>(256); /** 缓存单例的factory,就是objectfactory这个东西,: bean name --> objectfactory */ private final map<string, objectfactory<?>> singletonfactories = new hashmap<string, objectfactory<?>>(16); /** 也是缓存创建的单例对象,功能和singletonobjects不一样, 在bean构造成功之后,属性初始化之前会把对象放入到这里, 主要是用于解决属性注入的循环引用: bean name --> bean instance */ private final map<string, object> earlysingletonobjects = new hashmap<string, object>(16); /** 记录在创建单例对象中循环依赖的问题,还记得prototype中又记录创建过程中依赖的map吗? 在prototype中只要出现了循环依赖就抛出异常,而在单例中会尝试解决 */ private final set<string> singletonscurrentlyincreation = collections.newsetfrommap(new concurrenthashmap<string, boolean>(16));
现在回过来看getsingleton(beanname, new objectfactory<object>()这个方法的实现。
public object getsingleton(string beanname, objectfactory<?> singletonfactory) { synchronized (this.singletonobjects) { //尝试在singletonobjects中获取 object singletonobject = this.singletonobjects.get(beanname); if (singletonobject == null) { //不存在则创建 //把当前beanname加入到singletonscurrentlyincreation中 beforesingletoncreation(beanname); try { singletonobject = singletonfactory.getobject(); } ... finally { ... //从singletonscurrentlyincreation中删除beanname aftersingletoncreation(beanname); } } return (singletonobject != null_object ? singletonobject : null); } }
这段逻辑是不是和prototype中解决循环类似,这里其实就是调用了objectfactory的getobject()获取对象,回过头去看前面代码,objectfactory的getobject()方法实际调用的是createbean(beanname, mbd, args)。说到createbean(beanname, mbd, args)又不得不说abstractautowirecapablebeanfactory这个类,主要功能就是完成依赖注入的bean的创建,这个类的createbean方法代码如下,注意注解说明:
@override protected object createbean(string beanname, rootbeandefinition mbd, object[] args) throws beancreationexception { ... object beaninstance = docreatebean(beanname, mbdtouse, args); ... } protected object docreatebean(final string beanname, final rootbeandefinition mbd, final object[] args) throws beancreationexception { // 实例化bean beanwrapper instancewrapper = null; if (mbd.issingleton()) { instancewrapper = this.factorybeaninstancecache.remove(beanname); } if (instancewrapper == null) { //如果没实例化则创建新的beanwrapper //如果是通过构造器注入,这里是一个关键点 /* 因为在a初始化的时候发现构造函数依赖b,就会去实例化b, 然后b也会运行到这段逻辑,构造函数中发现依赖a, 这个时候就会抛出循环依赖的异常 */ instancewrapper = createbeaninstance(beanname, mbd, args); } //如果当前是单例,并且allowcircularreferences为true(默认就是true,除非我们不希望spring帮我们解决) boolean earlysingletonexposure = (mbd.issingleton() && this.allowcircularreferences && issingletoncurrentlyincreation(beanname)); if (earlysingletonexposure) { /* !!!这里很重要,把构造成功,但属性还没注入的 的bean加到singletonfactory中,这样再解决a的依赖 过程中如果依赖a,就把这个半成品返回回去。 */ addsingletonfactory(beanname, new objectfactory<object>() { @override public object getobject() throws beansexception { return getearlybeanreference(beanname, mbd, bean); } }); } object exposedobject = bean; try { //自动注入属性 populatebean(beanname, mbd, instancewrapper); if (exposedobject != null) { exposedobject = initializebean(beanname, exposedobject, mbd); } } ... return exposedobject; }
注解已经注明了我的理解。就不再赘述
总结
上面代码是我一边debug一个写下的,现在写完了,根据自己的理解总结一下。
相关类说明
abstractbeanfactory,这个类中包含了bean创建的主要流程,在dogetbean这个方法中包含了对prototype循环依赖处理。逻辑很简单,出现了循环依赖则直接抛出异常
defaultsingletonbeanregister 用于管理singleton的对象的创建,以及解决循环依赖的问题,其中解决循环依赖的关键属性就是了earlysingletonobjects,他会在构造singleton对象过程中暂时缓存构造成功,但属性还未注入的对象,这样就可以解决循环依赖的问题。
abstractautowirecapablebeanfactory,自动注入的相关逻辑,包自动注入的对象的创建、初始化和注入。但如果在调用构造函数中发现了循环依赖,则抛出异常
objectfactory,这个接口功能和factorybean类似,但是为了解决循环依赖,他决定了在获取的getsingleton()是一个完成品还是一个半成品。
思考
如果a--构造依赖->b,b--属性依赖-->a,例如:
@component public class beana { private beanb beanb; @autowired public beana(beanb beanb) { this.beanb = beanb; } } @component public class beanb { @autowired private beana beana; }
这种情况会异常吗?提示:都有可能
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Mysql命令大全(详细篇)