<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
之前我們有分析過Spring是怎麼解決迴圈參照的問題,主要思路就是三級快取;
Spring在載入beanA的時候會先呼叫預設的空建構函式(在沒有指定建構函式範例化的前提下)得到一個空的範例參照物件,這個時候沒有設定任何值,但是Spring會用快取把它給提前暴露出來,讓其他依賴beanA的bean可以持有它提前暴露的參照;
比如 a 依賴b ,b依賴a,並且他們都是通過預設方法範例化,那麼簡單流程是這樣的:
具體詳細一點可以看這篇文章Spring-bean的迴圈依賴以及解決方式
Spring不能解決“A的構造方法中依賴了B的範例物件,同時B依賴了A的範例物件”這類問題
這篇文章我想從原始碼的角度來分析一下整個流程;
並且分析一下Spring為什麼不能解決“A的構造方法中依賴了B的範例物件,同時B依賴了A的範例物件”這類問題
首先建立兩個bean類; CirculationA 有個屬性circulationB,並且有個建構函式給circulationB賦值;
public class CirculationA { private CirculationB circulationB; public CirculationA(CirculationB circulationB) { this.circulationB = circulationB; } }
CirculationB 有個屬性circulationA,然後set方法
public class CirculationB { private CirculationA circulationA; public CirculationA getCirculationA() { return circulationA; } public void setCirculationA(CirculationA circulationA) { this.circulationA = circulationA; } }
SpringContextConfig.xml circulationa 用給定的建構函式範例化;
circulationb 就用預設的範例化方法(預設的空建構函式)
<bean id="circulationa" class="src.bean.CirculationA"> <constructor-arg name="circulationB" ref="circulationb"/> </bean> <bean id="circulationb" class="src.bean.CirculationB" > <property name="circulationA" ref="circulationa"/> </bean>
好,例子準完畢,上面的例子是 circulationa的建構函式裡面有circulationb;
然後circulationb屬性裡面有circulationa;
結果如下:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circulationa' defined in class path resource [config.xml]: Cannot resolve reference to bean 'circulationb' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circulationb' defined in class path resource [config.xml]: Cannot resolve reference to bean 'circulationa' while setting bean property 'circulationA'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circulationa': Requested bean is currently in creation: Is there an unresolvable circular reference?
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circulationa' defined in class path resource [config.xml]: Cannot resolve reference to bean 'circulationb' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circulationb' defined in class path resource [config.xml]: Cannot resolve reference to bean 'circulationa' while setting bean property 'circulationA'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circulationa': Requested bean is currently in creation: Is there an unresolvable circular reference?
Disconnected from the target VM, address: '127.0.0.1:64128', transport: 'socket'
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:648)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:145)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1193)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at StartIOCUseDefaultListAbleBeanFactory.main(StartIOCUseDefaultListAbleBeanFactory.java:30)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circulationb' defined in class path resource [config.xml]: Cannot resolve reference to bean 'circulationa' while setting bean property 'circulationA'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circulationa': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1531)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
... 17 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circulationa': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:347)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
... 27 more
報錯了,Spring它解決不了這種情況 Ok,原始碼走起來: 為了節省篇幅我只貼重要程式碼 第一步
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } } }); } } public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { //在建立之前把beanName加入到正在建立中的屬性中singletonsCurrentlyInCreation; //但是這個是一個set,如果之前已經加進去了,再進去就拋異常BeanCurrentlyInCreationException //Requested bean is currently in creation: Is there an unresolvable circular reference?")提示可能存在迴圈參照 beforeSingletonCreation(beanName); } protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } } @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 { instanceWrapper = createBeanInstance(beanName, mbd, args); //....... // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } } } protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); //因為circulationa是有建構函式的,所以使用autowireConstructor if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } } //最終執行 public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs) { //解解建構函式引數值 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); //...... //選擇對應的策略來範例化物件;這裡是生成正在的範例了。 //但是在這之前,構造引數要拿到 beanInstance = this.beanFactory.getInstantiationStrategy().instantiate( mbd, beanName, this.beanFactory, constructorToUse, argsToUse); } }
省略....
/** * Resolve a reference to another bean in the factory. */ private Object resolveReference(Object argName, RuntimeBeanReference ref) { try { String refName = ref.getBeanName(); refName = String.valueOf(doEvaluate(refName)); if (ref.isToParent()) { if (this.beanFactory.getParentBeanFactory() == null) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Can't resolve reference to bean '" + refName + "' in parent factory: no parent factory available"); } //!!!這裡,要先去查詢refName的範例 return this.beanFactory.getParentBeanFactory().getBean(refName); } else { Object bean = this.beanFactory.getBean(refName); this.beanFactory.registerDependentBean(refName, this.beanName); return bean; } } catch (BeansException ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); } }
跟著上面的順序我們整理一下;
然後我們分析一下circulationb載入 circulationb跟circulationa差不多 載入circulationb,把它加入到正在建立的屬性中
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
然後用預設的方式建立範例; circulationa 是rautowireConstructor(beanName, mbd, ctors, args)建立的;這個方法需要先拿到建構函式的值;所以執行了呼叫getBean(circulationb)
circulationa是呼叫了instantiateBean;這個方法不需要提前知道屬性;它用預設的建構函式生成範例;這時候的範例是沒有設定任何屬性的;
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); }
不過生成了範例之後,在doCreateBean方法中有一個populateBean;這個方法就是專門填充屬性值的,因為circulationb有circulationa的屬性; 所以會去容器裡面取circulationa的參照;
但是circulationa這個時候還沒有成功建立範例啊;因為它還一直在等circulationb建立成功之後返回給它參照呢,返回了circulationa才能建立範例啊;
這個時候circulationb沒有拿到circulationa,那麼又會去呼叫getBean(circulationa); 大家想一想如果這樣下去就沒完沒了了啊; 所以Spring就丟擲異常了 那麼在哪裡丟擲異常呢? 在第二次呼叫getBean(circulationa)的時候會走到下面
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
因為circulationa之前加進來過一次啊,而且沒有建立成功是不會刪除的啊;
現在又add一次,因為this.singletonsCurrentlyInCreation是一個set;
已經存在的再次add會返回false;那麼這段程式碼就會丟擲異常了;
Error creating bean with name 'circulationa': Requested bean is currently in creation: Is there an unresolvable circular reference?
情況就是這樣,只要是用建構函式建立一個範例,並且建構函式裡包含的值存在迴圈參照,那麼spring就會丟擲異常;
所以如果有迴圈參照的情況請避免使用建構函式的方式
以上就是Spring迴圈參照失敗問題原始碼解析的詳細內容,更多關於Spring迴圈參照失敗的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45