SpringIOC DI循环依赖实例详解
要弄清楚循环依赖
1、需要知道Bean初始化的两个阶段
①Bean实例化创建实例对象(newBean())
②Bean实例对象初始化(DI:注解自动注入)
2、DefaultSingletonBeanRegistry类中的5个容器
/**记录已将创建的单例*/ privatefinalMap singletonObjects=newConcurrentHashMap<>(256); /**记录singletonFactory singeletonFactory中存放beanName和上面的①阶段的bean:Bean实例化实例对象(还未初始化DI)*/ privatefinalMap >singletonFactories=newHashMap<>(16); /**记录早期的singletonBean存放的也是①*/ privatefinalMap earlySingletonObjects=newHashMap<>(16); /**存放已经初始化后的beanName,有序*/ privatefinalSet registeredSingletons=newLinkedHashSet<>(256); /**记录正在初始化的bean的beanName*/ privatefinalSet singletonsCurrentlyInCreation=Collections.newSetFromMap(newConcurrentHashMap<>(16));
其中跟循环依赖相关的是singletonFactories、singeletonsCurrentlyInCreation、earlysingletonObjects.
3、循环依赖实现
①bean初始化前后会打标,加入到singletonsCurrentlyInCreation容器中,这个打标会在核心方法getSingleton()中起作用
/*org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String,org.springframework.beans.factory.ObjectFactory>)*/
publicObjectgetSingleton(StringbeanName,ObjectFactory>singletonFactory){
...
//循环依赖相关:初始化前先singletonsCurrentlyInCreation.add(beanName)
beforeSingletonCreation(beanName);
...
//lamda表达式:其实是调用createBean(beanName,mbd,args):Bean初始化
singletonObject=singletonFactory.getObject();
...
//循环依赖相关:初始化后singletonsCurrentlyInCreation.remove(beanName)
afterSingletonCreation(beanName);
...//初始化完后
//this.singletonObjects.put(beanName,singletonObject);放入到单例容器中
//this.singletonFactories.remove(beanName);清空循环依赖的两个打标
//this.earlySingletonObjects.remove(beanName);
//this.registeredSingletons.add(beanName);放入单例beanName容器中
addSingleton(beanName,singletonObject);
...
}
}
②上面singletonObject=singletonFactory.getObject()时向singletonFactories中记录了(newBean()),singletonFactories也会在核心方法getSingleton()中起作用
/*org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean*/
protectedObjectdoCreateBean(finalStringbeanName,finalRootBeanDefinitionmbd,final@NullableObject[]args)
throwsBeanCreationException{
...
//循环依赖相关逻辑:
//this.singletonFactories.put(beanName,singletonFactory);
//将实例化bean(①阶段)、beanName组装成singletonFactory装入singletonFactories容器
//this.earlySingletonObjects.remove(beanName);
//删除earlySingletonObjects中beanName
addSingletonFactory(beanName,()->getEarlyBeanReference(beanName,mbd,bean));
...
//实例初始化就是在这里面实现依赖注入DI的:反射实现
//调用AutowiredAnnotationBeanPostProcessor.postProcessProperties
populateBean(beanName,mbd,instanceWrapper);
...
}
③核心方法getSingleton
/*org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String,boolean)*/
protectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference){
ObjectsingletonObject=this.singletonObjects.get(beanName);
//循环依赖核心就在于这个判断,由于打标+记录了①阶段的bean,
//循环依赖第二次调用getBean("a")时,这里会直接返回第一次调用getBean("a")创建的①阶段的bean
//而不会调用createBean("a")再次bean初始化(造成两个bean的循环创建)
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);
}
}
}
}
returnsingletonObject;
}
④循环依赖流程
/*org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean*/ protectedTdoGetBean(finalStringname,@NullablefinalClass requiredType, @NullablefinalObject[]args,booleantypeCheckOnly)throwsBeansException{ ... //假设A、B互相依赖 //第一次getBean(A),sharedInstance==null,走else,createBean //A正在创建打标,①中beforeSingletonCreation() //A实例化后保存到singletonFactories中②中addSingletonFactory(beanName,singletonFactory) //DI依赖注入:②中populateBean(beanName,mbd,instanceWrapper),发现依赖B,调用getBean(B)初始化B的单例 //调用getBean(B)重复上面步骤,DI依赖注入发现依赖A,调用getBean(A) //第二次getBean(A),③中if(singletonObject==null&&isSingletonCurrentlyInCreation(A))由于打标了所以返回singleFactory.getObject() //下面if条件直接返回bean,没有走else破坏了循环 ObjectsharedInstance=getSingleton(beanName); if(sharedInstance!=null&&args==null){ // bean=getObjectForBeanInstance(sharedInstance,name,beanName,null); } else{ ... // createBean(beanName,mbd,args); bean=getObjectForBeanInstance(sharedInstance,name,beanName,null); } returnbean; }
四、总结
未看源码之前,其实对循环依赖有一个想法:循环依赖可以看做是一个死锁。
预防死锁的方法:打破死锁的四个必要条件(互斥、请求并等待、不可剥夺、循环等待),由于循环依赖的资源是对象自身,所以常用破坏循环等待条件方法:编号顺序执行,不适用
选择破坏请求并等待条件:先创建对象,再赋值,模型
Aa=newA();
Bb=newB();
A.b=b;
B.a=a;
研究源码之后发现:想法差不多,但是代码实现非常精彩。模型(打标没想到过)
Aa=newA();
Bb=newB();
b.a=a;
a.b=b;
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。