Spring IOC 循环依赖
Spring IOC 循环依赖
1. 概述
Spring循环依赖是使用Spring过程中容易遇到的问题,这篇文章主要讲Spring如何处理循环依赖问题。这里主要讲的是Spring解决一般单例对象的循环依赖问题。注入方式如下:
- <bean class="com.kanyuxia.spring.bean.constructandsetter.Dog" name="dog" lazy-init="true">
- <property name="pig" ref="pig" />
- </bean>
2. Spring IOC对Bean的初始化
由于涉及到Spring对于一般单例对象的循环依赖问题,所以先简单看一下Spring对单例对象的初始化过程。这里主要讲了大概的初始化过程,对于特殊情况,如ProxyBean、FactoryBean等没有进行详细的说明。
2.1 大概流程如下
- 从Resource(如XML)中读取Bean的定义并把其初始化为BeanDefinition对象。这里,当Bean的lazy-init属性为true时,不进行Bean的初始化
- 当调用Spring容器的AbstractBeanFactory.getBean(beanName)方法时,Spring正式开始初始化Bean。首先通过DefaultSingletonBeanRegistry.getSingleton()方法从缓存获取Bean,例如lazy-init为false时Bean对象已经创建并放入缓存中,或者当解决循环依赖时也是在缓存中读取
- 如果从缓存中没有获取Bean则需要创建Bean,通过调用AbstractAutoWireCapableBeanFactory.createBean()方法创建Bean
- 调用AbstractAutoWireCapableBeanFactory.createBeanInstance()方法实例化Bean。
- 调用DefaultSingletonBeanRegistry.addSingletonFactory()方法添加一个SingletonFactory缓存,这里是Spring解决循环依赖的关键点
- 调用AbstractAutoWireCapableBeanFactory.populateBean()方法为Bean填充属性。
- 调用AbstractAutoWireCapableBeanFactory.initializeBean()方法来初始化Bean,调用Bean时的init()方法、工厂回调、Bean Post处理器等等
2.2 流程图如下 (画的不好,见谅)
2.3 相关代码如下
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);
- if (sharedInstance != null && args == null) {
- // 省略.....
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
- } else {
- // 省略......
- // Create bean instance.
- if (mbd.isSingleton()) {
- sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
-
- public Object getObject() throws BeansException {
- try {
- return createBean(beanName, mbd, args);
- } catch (BeansException ex) {
- destroySingleton(beanName);
- throw ex;
- }
- }
- });
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
- }
- // 省略......
- }
DefaultSingletonBeanRegistry的两个getSingleton()方法,一个从缓存中读取Bean,另一个通过调用ObjectFactory创建Bean
- /**
- * Return the (raw) singleton object registered under the given name.
- * <p>Checks already instantiated singletons and also allows for an early
- * reference to a currently created singleton (resolving a circular reference).
- * @param beanName the name of the bean to look for
- * @param allowEarlyReference whether early references should be created or not
- * @return the registered singleton object, or {@code null} if none found
- */
- 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);
- }
- /**
- * Return the (raw) singleton object registered under the given name,
- * creating and registering a new one if none registered yet.
- * @param beanName the name of the bean
- * @param singletonFactory the ObjectFactory to lazily create the singleton
- * with, if necessary
- * @return the registered singleton object
- */
- public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
- synchronized (this.singletonObjects) {
- Object singletonObject = this.singletonObjects.get(beanName);
- if (singletonObject == null) {
- // 省略......
- try {
- singletonObject = singletonFactory.getObject();
- newSingleton = true;
- }
- catch (IllegalStateException ex) {
- // 省略......
- }
- catch (BeanCreationException ex) {
- // 省略......;
- }
- finally {
- // 省略......
- afterSingletonCreation(beanName);
- }
- if (newSingleton) {
- addSingleton(beanName, singletonObject);
- }
- }
- return (singletonObject != NULL_OBJECT ? singletonObject : null);
- }
- }
这里先从从缓存中拿Bean(这里解决的依赖注入问题),没有则通过创建一个匿名ObjectFactory对象来创建对象。
然后就是createBean(),下面是AbstractAutowireCapableBeanFactory.doCreateBean()方法
- /**
- * Actually create the specified bean. Pre-creation processing has already happened
- * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
- * <p>Differentiates between default bean instantiation, use of a
- * factory method, and autowiring a constructor.
- * @param beanName the name of the bean
- * @param mbd the merged bean definition for the bean
- * @param args explicit arguments to use for constructor or factory method invocation
- * @return a new instance of the bean
- * @throws BeanCreationException if the bean could not be created
- * @see #instantiateBean
- * @see #instantiateUsingFactoryMethod
- * @see #autowireConstructor
- */
- protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {
- // 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);
- mbd.resolvedTargetType = beanType;
- // 省略......
- // 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) {
- // 省略......
- addSingletonFactory(beanName, new ObjectFactory<Object>() {
-
- 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) {
- // 省略......
- }
- // 省略......
- // Register bean as disposable.
- try {
- registerDisposableBeanIfNecessary(beanName, bean, mbd);
- } catch (BeanDefinitionValidationException ex) {
- // 省略......
- }
- return exposedObject;
- }
3. Spring IOC对Bean循环依赖的解决方案
3.1 循环依赖
循环依赖指的是多个对象之间相互依赖,例如A对象依赖B对象,B对象依赖A对象,这样就形成了一个环。Java中循环依赖主要有以下几种情况:
- A的构造方法依赖B对象,同时B对象的构造方法依赖于A
- A的构造方法依赖B对象,同时B对象的Field依赖于A
- A的Filed依赖B对象,同时B对象的构造方法依赖于A
- A的Filed依赖B对象,同时B对象的Filed依赖于A
3.3 Spring的解决方案
从前面看的出来,Spring对Singleton对象的初始化有四步:
- 从缓存中取Bean
- createBeanInstance,实例化Bean对象,就是通过构造方法构造Bean对象。当构造完成后会缓存一个singletonFactory,这里解决的依赖注入问题
- populateBean,填充对象属性,这里会对Bean的属性进行注入
- initialzeBean,实例化Bean,这里主要是注入Bean的特殊属性
所以从上面我们可以看出Spring可以解决第3、第4种情况下的依赖注入,对于第1、第2种则没有办法解决,会抛出BeanCurrentlyInCreationException异常。
下面是主要代码逻辑:
首先从缓存中去取Bean
// Cache of singleton objects: bean name --> bean instance
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
// Cache of singleton factories: bean name --> ObjectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
// Cache of early singleton objects: bean name --> bean instance
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
这里主要涉及到以上三种Spring对Singleton Bean的缓存
- /**
- * Return the (raw) singleton object registered under the given name.
- * <p>Checks already instantiated singletons and also allows for an early
- * reference to a currently created singleton (resolving a circular reference).
- * @param beanName the name of the bean to look for
- * @param allowEarlyReference whether early references should be created or not
- * @return the registered singleton object, or {@code null} if none found
- */
- 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);
- }
从代码中可以看出Spring会依次从三种缓存中去取Singleton Bean
当Bean调用createBeanInstance()方法(构造Bean)后会调用addSingletonFactory()方法把构造的Singleton Bean通过ObjectFactory存放到singletonFactory缓存中。
- protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {
- // 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);
- // 省略......
- // 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()) {
- // 省略......
- }
- addSingletonFactory(beanName, new ObjectFactory<Object>() {
-
- public Object getObject() throws BeansException {
- return getEarlyBeanReference(beanName, mbd, bean);
- }
- });
- }
- }
-
- /**
- * Add the given singleton factory for building the specified singleton if necessary.
- * <p>To be called for eager registration of singletons, e.g. to be able to
- * resolve circular references.
- * @param beanName the name of the bean
- * @param singletonFactory the factory for the singleton object
- */
- 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);
- }
- }
- }
这里通过缓存ObjectFactory提前把Singleton Bean暴露出来了,后面在进行构造其他对象时可以直接从缓存中取,这里就解决的循环依赖问题。
4. References
https://www.jianshu.com/p/6c359768b1dc
https://www.jianshu.com/p/ecc60703d315
https://www.jianshu.com/p/d76318d09b22