Spring中如何解决循环依赖,简单举个下面这样例子
- A类中注入了B类对象
- B类中注入了A类对象
如果是通过构造函数注入,那么在初始化时的时候会报循环注入。A初始化时B可能尚未初始化。
反之,如果是通过get set这种注入或者@Autowired 注入,并且是singelton(默认)而非prototype则不会报错。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。spring通过提前暴露一个单例工厂方法,从而使其他bean能引用到该bean。
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.containsKey(beanName) && this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) { throw new BeanCurrentlyInCreationException(beanName); } }
1.从源码中可以看出,A实例化时会去singletonsCurrentlyInCreation写入A,A中依赖B因此,需要实例化B,B中依赖A,因此需要实例A,而A之前已经在Increation,因此会报错。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { // Instantiate the bean. //..... // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. 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() { public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } // ...... }protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (singletonObject) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory objectFactory = this.singletonFactories.get(beanName); if (objectFactory != null) { singletonObject = objectFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT) ? singletonObject : null; }
2.采用set方法时,Spring略有不同,A实例化时会将一个 A的实例引用写入objectFactory中。执行setB时去实例化B,B的setA调用getSingleton(A,true),因为A 实例还在创建中,会接着往下执行,最终通过objectFactory返回A的实例引用,之后删除factory,缓存A的引用。