当spring的bean存在循环引用时,有的情况下会报错,而有的情况下不会。影响是否会报错的因素是:1.属性是通过构造方法传递值还是通过setter传递值。2.属性是否是单例的。下面解释了四种情况、是否会报错、报错或不报错的原因。
前置知识
不论是singleton
还是prototype
,在创建的过程中都会有一个xxxCurrentlyInCreation的Set对象,这个Set中存放的key表示正在创建的对象,但是还没有创建完成。在对象new之前先检查这个Set中没有要创建的key,然后把要创建的对象的key放入Set,等对象完全创建完成后再把key从Set中移除;在对象创建前检查这个Set中存在要创建的key时,则抛出org.springframework.beans.factory.BeanCurrentlyInCreationException
这个类型的异常。
对于singleton
的对象,在创建的过程中,在创建完对象以后,setter方法执行前,会放到org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.singletonFactories
属性中,以供后面依赖的对象创建时使用。
这里区别一下上面的过程的先后顺序。当getBean的时候,如果是单例,则先从之前缓存的对象中取,如果有则直接返回。否则去new,new的时候再用xxxCurrentlyInCreation的Set去去重,如果在xxxCurrentlyInCreation的Set中则抛异常。
在后面的解释中,我们假设一个a -> b -> a
的循环依赖。
setter - singleton
不报错。
原因:singleton的对象创建的过程中,会被存放进org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.singletonFactories
属性中,在后面的依赖循环中需要这个单例的对象时,在这个map中取出即可。
那这个对象时在何时被put的呢? 在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean
-> org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.addSingletonFactory
中,在上述的doCreateBean中调用addSingletonFactory方法的地方还有一句注释: Eagerly cache singletons to be able to resolve circular references even when triggered by lifecycle interfaces like BeanFactoryAware.
。
a
对象创建完,被put到org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.singletonFactories
,然后在执行a
的setter中依赖b,构造b的过程中依赖a,这时a已经在map中了,可以直接获取,而不需要再new。
setter - prototype
报错。错误如下。
org.springframework.beans.factory.BeanCurrentlyInCreationException Requested bean is currently in creation: Is there an unresolvable circular reference?
原因:getBean的时候,先构造a对象,然后通过setter方法设置属性,设置的时候构造依赖的对象b。new b完成,然后执行setter,需要构造a,这时a已经在xxxInCreation的Set中,所以抛异常。
construct - singleton
报错。错误如下。
org.springframework.beans.factory.BeanCurrentlyInCreationException Requested bean is currently in creation: Is there an unresolvable circular reference?
原因:getBean的时候,检查构造方法,创建构造方法里需要的对象,所以成环。相比于 setter - singleton
这种情况,它抛了异常,而setter - singleton
没有抛出异常,区别在哪里呢?因为把单例对象放入org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.singletonFactories
的时机是在对象创建后,setter方法执行前。这种情况下在执行构造方法的过程中的依赖,所以之前第一个a
还没有构造完成,还没有被放进org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.singletonFactories
。
construct - prototype
报错。错误如下。
org.springframework.beans.factory.BeanCurrentlyInCreationException Requested bean is currently in creation: Is there an unresolvable circular reference?
原因:getBean的时候,检查构造方法,创建构造方法里需要的对象。所以成环。