详解Spring循环依赖的解决方案
spring针对bean之间的循环依赖,有自己的处理方案。关键点就是三级缓存。当然这种方案不能解决所有的问题,他只能解决bean单例模式下非构造函数的循环依赖。
我们就从a->b->c-a这个初始化顺序,也就是a的bean中需要b的实例,b的bean中需要c的实例,c的bean中需要a的实例,当然这种需要不是构造函数那种依赖。前提条件有了,我们就可以开始了。毫无疑问,我们会先初始化a.初始化的方法是org.springframework.beans.factory.support.abstractbeanfactory#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; // eagerly check singleton cache for manually registered singletons. object sharedinstance = getsingleton(beanname); //关注点1 if (sharedinstance != null && args == null) { if (logger.isdebugenabled()) { if (issingletoncurrentlyincreation(beanname)) { logger.debug("returning eagerly cached instance of singleton bean '" + beanname + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("returning cached instance of singleton bean '" + beanname + "'"); } } bean = getobjectforbeaninstance(sharedinstance, name, beanname, null); } else { // fail if we're already creating this bean instance: // we're assumably within a circular reference. if (isprototypecurrentlyincreation(beanname)) { throw new beancurrentlyincreationexception(beanname); } // check if bean definition exists in this factory. beanfactory parentbeanfactory = getparentbeanfactory(); if (parentbeanfactory != null && !containsbeandefinition(beanname)) { // not found -> check parent. string nametolookup = originalbeanname(name); if (args != null) { // delegation to parent with explicit args. return (t) parentbeanfactory.getbean(nametolookup, args); } else { // no args -> delegate to standard getbean method. return parentbeanfactory.getbean(nametolookup, requiredtype); } } if (!typecheckonly) { markbeanascreated(beanname); } try { final rootbeandefinition mbd = getmergedlocalbeandefinition(beanname); checkmergedbeandefinition(mbd, beanname, args); // guarantee initialization of beans that the current bean depends on. string[] dependson = mbd.getdependson(); if (dependson != null) { for (string dependsonbean : dependson) { if (isdependent(beanname, dependsonbean)) { throw new beancreationexception(mbd.getresourcedescription(), beanname, "circular depends-on relationship between '" + beanname + "' and '" + dependsonbean + "'"); } registerdependentbean(dependsonbean, beanname); getbean(dependsonbean); } } // create bean instance. if (mbd.issingleton()) { //关注点2 sharedinstance = getsingleton(beanname, new objectfactory<object>() { @override public object getobject() throws beansexception { try { return createbean(beanname, mbd, args); } catch (beansexception ex) { // explicitly remove instance from singleton cache: it might have been put there // eagerly by the creation process, to allow for circular reference resolution. // also remove any beans that received a temporary reference to the bean. destroysingleton(beanname); throw ex; } } }); bean = getobjectforbeaninstance(sharedinstance, name, beanname, mbd); } else if (mbd.isprototype()) { // it's a prototype -> create a new instance. object prototypeinstance = null; try { beforeprototypecreation(beanname); prototypeinstance = createbean(beanname, mbd, args); } finally { afterprototypecreation(beanname); } bean = getobjectforbeaninstance(prototypeinstance, name, beanname, mbd); } else { string scopename = mbd.getscope(); final scope scope = this.scopes.get(scopename); if (scope == null) { throw new illegalstateexception("no scope registered for scope name '" + scopename + "'"); } try { object scopedinstance = scope.get(beanname, new objectfactory<object>() { @override public object getobject() throws beansexception { beforeprototypecreation(beanname); try { return createbean(beanname, mbd, args); } finally { afterprototypecreation(beanname); } } }); bean = getobjectforbeaninstance(scopedinstance, name, beanname, mbd); } catch (illegalstateexception ex) { throw new beancreationexception(beanname, "scope '" + scopename + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (beansexception ex) { cleanupafterbeancreationfailure(beanname); throw ex; } } // check if required type matches the type of the actual bean instance. if (requiredtype != null && bean != null && !requiredtype.isassignablefrom(bean.getclass())) { try { return gettypeconverter().convertifnecessary(bean, requiredtype); } catch (typemismatchexception ex) { if (logger.isdebugenabled()) { logger.debug("failed to convert bean '" + name + "' to required type [" + classutils.getqualifiedname(requiredtype) + "]", ex); } throw new beannotofrequiredtypeexception(name, requiredtype, bean.getclass()); } } return (t) bean; }
这个方法很长我们一点点说。先看我们的关注点1 object sharedinstance = getsingleton(beanname
)根据名称从单例的集合中获取单例对象,我们看下这个方法,他最终是org.springframework.beans.factory.support.defaultsingletonbeanregistry#getsingleton(java.lang.string, boolean)
protected object getsingleton(string beanname, boolean allowearlyreference) { object singletonobject = 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); }
大家一定要注意这个方法,很关键,我们开篇提到了三级缓存,使用点之一就是这里。到底是哪三级缓存呢,第一级缓存singletonobjects
里面放置的是实例化好的单例对象。第二级earlysingletonobjects
里面存放的是提前曝光的单例对象(没有完全装配好)。第三级singletonfactories里面存放的是要被实例化的对象的对象工厂。解释好了三级缓存,我们再看看逻辑。第一次进来this.singletonobjects.get(beanname)
返回的肯定是null。然后issingletoncurrentlyincreation
决定了能否进入二级缓存中获取数据。
public boolean issingletoncurrentlyincreation(string beanname) { return this.singletonscurrentlyincreation.contains(beanname); }
从singletonscurrentlyincreation
这个set中有没有包含传入的beanname,前面没有地方设置,所以肯定不包含,所以这个方法返回false,后面的流程就不走了。getsingleton
这个方法返回的是null。
下面我们看下关注点2.也是一个getsingleton
只不过他是真实的创建bean的过程,我们可以看到传入了一个匿名的objectfactory的对象,他的getobject方法中调用的是createbean这个真正的创建bean的方法。当然我们可以先搁置一下,继续看我们的getsingleton
方法
public object getsingleton(string beanname, objectfactory<?> singletonfactory) { assert.notnull(beanname, "'beanname' must not be null"); synchronized (this.singletonobjects) { object singletonobject = this.singletonobjects.get(beanname); if (singletonobject == null) { if (this.singletonscurrentlyindestruction) { throw new beancreationnotallowedexception(beanname, "singleton bean creation not allowed while the singletons of this factory are in destruction " + "(do not request a bean from a beanfactory in a destroy method implementation!)"); } if (logger.isdebugenabled()) { logger.debug("creating shared instance of singleton bean '" + beanname + "'"); } beforesingletoncreation(beanname); boolean newsingleton = false; boolean recordsuppressedexceptions = (this.suppressedexceptions == null); if (recordsuppressedexceptions) { this.suppressedexceptions = new linkedhashset<exception>(); } try { singletonobject = singletonfactory.getobject(); newsingleton = true; } catch (illegalstateexception ex) { // has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonobject = this.singletonobjects.get(beanname); if (singletonobject == null) { throw ex; } } catch (beancreationexception ex) { if (recordsuppressedexceptions) { for (exception suppressedexception : this.suppressedexceptions) { ex.addrelatedcause(suppressedexception); } } throw ex; } finally { if (recordsuppressedexceptions) { this.suppressedexceptions = null; } aftersingletoncreation(beanname); } if (newsingleton) { addsingleton(beanname, singletonobject); } } return (singletonobject != null_object ? singletonobject : null); } }
这个方法的第一句object singletonobject = this.singletonobjects.get(beanname)
从一级缓存中取数据,肯定是null。随后就调用的beforesingletoncreation
方法。
protected void beforesingletoncreation(string beanname) { if (!this.increationcheckexclusions.contains(beanname) && !this.singletonscurrentlyincreation.add(beanname)) { throw new beancurrentlyincreationexception(beanname); } }
其中就有往singletonscurrentlyincreation
这个set中添加beanname的过程,这个set很重要,后面会用到。随后就是调用singletonfactory的getobject方法进行真正的创建过程,下面我们看下刚刚上文提到的真正的创建的过程createbean
,它里面的核心逻辑是docreatebean
.
protected object docreatebean(final string beanname, final rootbeandefinition mbd, final object[] args) { // instantiate the bean. beanwrapper instancewrapper = null; if (mbd.issingleton()) { instancewrapper = this.factorybeaninstancecache.remove(beanname); } if (instancewrapper == null) { instancewrapper = createbeaninstance(beanname, mbd, args); } final object bean = (instancewrapper != null ? instancewrapper.getwrappedinstance() : null); class<?> beantype = (instancewrapper != null ? instancewrapper.getwrappedclass() : null); // allow post-processors to modify the merged bean definition. synchronized (mbd.postprocessinglock) { if (!mbd.postprocessed) { applymergedbeandefinitionpostprocessors(mbd, beantype, beanname); mbd.postprocessed = true; } } // eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like beanfactoryaware. //关注点3 boolean earlysingletonexposure = (mbd.issingleton() && this.allowcircularreferences && issingletoncurrentlyincreation(beanname)); if (earlysingletonexposure) { if (logger.isdebugenabled()) { logger.debug("eagerly caching bean '" + beanname + "' to allow for resolving potential circular references"); } addsingletonfactory(beanname, new objectfactory<object>() { @override public object getobject() throws beansexception { return getearlybeanreference(beanname, mbd, bean); } }); } // initialize the bean instance. object exposedobject = bean; try { populatebean(beanname, mbd, instancewrapper); if (exposedobject != null) { exposedobject = initializebean(beanname, exposedobject, mbd); } } catch (throwable ex) { if (ex instanceof beancreationexception && beanname.equals(((beancreationexception) ex).getbeanname())) { throw (beancreationexception) ex; } else { throw new beancreationexception(mbd.getresourcedescription(), beanname, "initialization of bean failed", ex); } } if (earlysingletonexposure) { object earlysingletonreference = getsingleton(beanname, false); if (earlysingletonreference != null) { if (exposedobject == bean) { exposedobject = earlysingletonreference; } else if (!this.allowrawinjectiondespitewrapping && hasdependentbean(beanname)) { string[] dependentbeans = getdependentbeans(beanname); set<string> actualdependentbeans = new linkedhashset<string>(dependentbeans.length); for (string dependentbean : dependentbeans) { if (!removesingletonifcreatedfortypecheckonly(dependentbean)) { actualdependentbeans.add(dependentbean); } } if (!actualdependentbeans.isempty()) { throw new beancurrentlyincreationexception(beanname, "bean with name '" + beanname + "' has been injected into other beans [" + stringutils.collectiontocommadelimitedstring(actualdependentbeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. this means that said other beans do not use the final version of the " + "bean. this is often the result of over-eager type matching - consider using " + "'getbeannamesoftype' with the 'alloweagerinit' flag turned off, for example."); } } } } // register bean as disposable. try { registerdisposablebeanifnecessary(beanname, bean, mbd); } catch (beandefinitionvalidationexception ex) { throw new beancreationexception(mbd.getresourcedescription(), beanname, "invalid destruction signature", ex); } return exposedobject; }
createbeaninstance
利用反射创建了对象,下面我们看看关注点3 earlysingletonexposure
属性值的判断,其中有一个判断点就是issingletoncurrentlyincreation(beanname)
public boolean issingletoncurrentlyincreation(string beanname) { return this.singletonscurrentlyincreation.contains(beanname); }
发现使用的是singletonscurrentlyincreation这个set,上文的步骤中已经将beanname已经填充进去了,所以可以查到,所以earlysingletonexposure
这个属性是结合其他的条件综合判断为true,进行下面的流程addsingletonfactory
,这里是为这个bean添加objectfactory,这个beanname(a)对应的对象工厂,他的getobject方法的实现是通过getearlybeanreference
这个方法实现的。首先我们看下addsingletonfactory的实现
protected void addsingletonfactory(string beanname, objectfactory<?> singletonfactory) { assert.notnull(singletonfactory, "singleton factory must not be null"); synchronized (this.singletonobjects) { if (!this.singletonobjects.containskey(beanname)) { this.singletonfactories.put(beanname, singletonfactory); this.earlysingletonobjects.remove(beanname); this.registeredsingletons.add(beanname); } } }
往第三级缓存singletonfactories存放数据,清除第二级缓存根据beanname的数据。这里有个很重要的点,是往三级缓存里面set了值,这是spring处理循环依赖的核心点。getearlybeanreference
这个方法是getobject的实现,可以简单认为是返回了一个为填充完毕的a的对象实例。设置完三级缓存后,就开始了填充a对象属性的过程。下面这段描述,没有源码提示,只是简单的介绍一下。
填充a的时候,发现需要b类型的bean,于是继续调用getbean方法创建,记性的流程和上面a的完全一致,然后到了填充c类型的bean的过程,同样的调用getbean(c)来执行,同样到了填充属性a的时候,调用了getbean(a),我们从这里继续说,调用了dogetbean中的object sharedinstance = getsingleton(beanname),
相同的代码,但是处理逻辑完全不一样了。
protected object getsingleton(string beanname, boolean allowearlyreference) { object singletonobject = 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); }
还是从singletonobjects获取对象获取不到,因为a是在singletonscurrentlyincreation
这个set中,所以进入了下面的逻辑,从二级缓存earlysingletonobjects
中取,还是没有查到,然后从三级缓存singletonfactories
找到对应的对象工厂调用getobject
方法获取未完全填充完毕的a的实例对象,然后删除三级缓存的数据,填充二级缓存的数据,返回这个对象a。c依赖a的实例填充完毕了,虽然这个a是不完整的。不管怎么样c式填充完了,就可以将c放到一级缓存singletonobjects
同时清理二级和三级缓存的数据。同样的流程b依赖的c填充好了,b也就填充好了,同理a依赖的b填充好了,a也就填充好了。spring就是通过这种方式来解决循环引用的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。