解析spring循环依赖

循环依赖

所谓循环依赖就是多个Bean之间依赖关系造成一个闭环,例如A->B->C->...->A 这种状况,固然,最简单的循环依赖就是2个Bean之间互相依赖:A->B(A依赖B), B->A(B依赖A) 。在Spring中,若是A->B,那么在建立A的过程当中会去建立B,在建立B(或B的依赖)的过程当中又发现B->A,这个时候就出现了循环依赖的现象。spring

循环依赖的解决

spring中的循环依赖只有当缓存

  1. Bean是单例,
  2. 经过属性注入的状况

这两个条件知足的状况下是没问题的。可是若是是经过构造器依赖,或者不是单例模式的状况下循环依赖就会抛出异常BeanCurrentlyInCreationException。下面从代码层面上解析一下为何。app

Prototype的循环依赖问题

为何最早介绍Prototype的循环依赖呢,由于能够顺便介绍在Spring中建立Bean的流程核心流程:在AbstractFoctory的doGetBean的方法。这个方法很长,这里只写出核心逻辑,并在注解上注明了我的理解:ide

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;
    
    //尝试获取单例对象,由于spring大部分的bean都是单例的,因此这里先尝试可否获取。
    registered singletons.
    Object sharedInstance = getSingleton(beanName);
    //单例存在的状况下,那么beanName返回的确定是单例类,可是这里还须要判断是否是FactoryBean
    if (sharedInstance != null && args == null) {
        ...
        //FactoryBean应该返回getObject()对象
    	bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    
    else {
        //走到这里,有可能beanName是单例模式,但以前并无实例化,或者是Prototype类型。
        //首先判断不是循环依赖,这里的循环依赖指的是Prototype类型
    	if (isPrototypeCurrentlyInCreation(beanName)) {
    		throw new BeanCurrentlyInCreationException(beanName);
    	}
    
    
    	try {
    		final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    		// 若是是单例,则建立单例模式
    		if (mbd.isSingleton()) {
    		    // !!!这里是解决单例循环依赖的关键,后面再分析
    			sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
    				@Override
    				public Object getObject() throws BeansException {
    					try {
    						return createBean(beanName, mbd, args);
    					}
    					catch (BeansException ex) {
    						throw ex;
    					}
    				}
    			});
    			bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    		}
    
    		else if (mbd.isPrototype()) {
    			// 原型模式,则建立一个新对象.
    			Object prototypeInstance = null;
    			try {
    			    /*这里是Prototype循环依赖的问题,会记录在map中beanName,
    			    若是在解决当前Bean的依赖过程当中还依赖当前Bean,
    			    则说明了出现了循环依赖
    			    */
                            beforePrototypeCreation(beanName);
                            prototypeInstance = createBean(beanName, mbd, args);
    			}
    			finally {
    			    //对应beforePrototypeCreation(),从map中移除
                            afterPrototypeCreation(beanName);
    			}
    			bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    		}
    		...
    	}
    }
    
    ...
    return (T) bean;
    }

能够看出,该流程中就考虑了Prototype的循环依赖的问题,只要在建立Prototype的Bean中出现循环依赖那么就抛出异常。可是在singleton的状况下,则经过另外的方式来解决。函数

Singleton的循环依赖之构造注入

在上面介绍中,出现了一个很关键的地方:ui

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
    @Override
    public Object getObject() throws BeansException {
    	try {
            return createBean(beanName, mbd, args);
    	}
    	catch (BeansException ex) {
            throw ex;
    	}
    }
});

这个getSingleton涉及到了ObjectFactory这个接口类,这个接口的功能和FactoryBean相似,可是主要是用来解决循环依赖的。在初始化过程同决定返回的Singleton对象是。关于单例的对象的建立,又要介绍一下DefaultSingletonBeanRegistry这个类,这个类主要用来帮助建立单例模式,其中主要的属性:this

/** 缓存建立的单例对象: bean名字 --> bean对象 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** 缓存单例的factory,就是ObjectFactory这个东西,: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/** 也是缓存建立的单例对象,功能和singletonObjects不同,
在bean构形成功以后,属性初始化以前会把对象放入到这里,
主要是用于解决属性注入的循环引用: bean name --> bean instance 
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

/** 记录在建立单例对象中循环依赖的问题,还记得Prototype中又记录建立过程当中依赖的map吗?
在Prototype中只要出现了循环依赖就抛出异常,而在单例中会尝试解决 */
private final Set<String> singletonsCurrentlyInCreation =
		Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));

如今回过来看getSingleton(beanName, new ObjectFactory<Object>()这个方法的实现。prototype

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {

    synchronized (this.singletonObjects) {
        //尝试在singletonObjects中获取
    	Object singletonObject = this.singletonObjects.get(beanName);
    	if (singletonObject == null) {
    		//不存在则建立
    		//把当前beanName加入到singletonsCurrentlyInCreation中
    		beforeSingletonCreation(beanName);
    		try {
    		    
    			singletonObject = singletonFactory.getObject();
    		}
    		...
    		finally {
    			...
    			//从singletonsCurrentlyInCreation中删除beanName
    			afterSingletonCreation(beanName);
    		}
    	}
    	return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
}

这段逻辑是否是和Prototype中解决循环相似,这里其实就是调用了ObjectFactory的getObject()获取对象,回过头去看前面代码,ObjectFactory的getObject()方法实际调用的是createBean(beanName, mbd, args)。说到createBean(beanName, mbd, args)又不得不说AbstractAutowireCapableBeanFactory这个类,主要功能就是完成依赖注入的Bean的建立,这个类的createBean方法代码以下,注意注解说明:debug

@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 {

	// 实例化bean
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
	    //若是没实例化则建立新的BeanWrapper
	    //若是是经过构造器注入,这里是一个关键点
	    /*
	    由于在A初始化的时候发现构造函数依赖B,就会去实例化B,
	    而后B也会运行到这段逻辑,构造函数中发现依赖A,
	    这个时候就会抛出循环依赖的异常
	    */
                instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	

   //若是当前是单例,而且allowCircularReferences为true(默认就是true,除非咱们不但愿Spring帮咱们解决)
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		/*
		!!!这里很重要,把构形成功,但属性还没注入的
		的bean加到singletonFactory中,这样再解决A的依赖
		过程当中若是依赖A,就把这个半成品返回回去。
		*/
		addSingletonFactory(beanName, new ObjectFactory<Object>() {
			@Override
			public Object getObject() throws BeansException {
				return getEarlyBeanReference(beanName, mbd, bean);
			}
		});
	}

	
	Object exposedObject = bean;
	try {
	    //自动注入属性
		populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
	}
    ...

	return exposedObject;
}

注解已经注明了个人理解。就再也不赘述code

总结

上面代码是我一边debug一个写下的,如今写完了,根据本身的理解总结一下。

相关类说明

image

  • AbstractBeanFactory,这个类中包含了Bean建立的主要流程,在doGetBean这个方法中包含了对Prototype循环依赖处理。逻辑很简单,出现了循环依赖则直接抛出异常
  • DefaultSingletonBeanRegister 用于管理Singleton的对象的建立,以及解决循环依赖的问题,其中解决循环依赖的关键属性就是了earlySingletonObjects,他会在构造Singleton对象过程当中暂时缓存构形成功,但属性还未注入的对象,这样就能够解决循环依赖的问题。
  • AbstractAutowireCapableBeanFactory,自动注入的相关逻辑,包自动注入的对象的建立、初始化和注入。但若是在调用构造函数中发现了循环依赖,则抛出异常
  • ObjectFactory,这个接口功能和FactoryBean相似,可是为了解决循环依赖,他决定了在获取的getSingleton()是一个完成品仍是一个半成品。

思考

若是A--构造依赖->B,B--属性依赖-->A,例如:

@Component
public class BeanA {
    private BeanB beanB;

    @Autowired
    public BeanA(BeanB beanB) {
        this.beanB = beanB;
    }
}

@Component
public class BeanB {
    @Autowired
    private BeanA beanA;
}

这种状况会异常吗?提示:都有可能

相关文章
相关标签/搜索