追溯IOC循环依赖处理

追溯IOC循环依赖处理

前言

循环依赖是指多个类存在直接或间接依赖关系,最终形成一个闭环调用。如下图,A依赖B,B依赖C,C依赖A:

image-20210730200115421.png

而Spring中循环依赖有三种:

  • 构造器注入
  • setter注入(单例,默认形式)
  • setter注入(原型,prototype)

本文主要是对Spring对于这三种依赖分别是怎么处理的一次源码追溯记录。

测试代码

A,B,C三个类相互依赖

public class A {
    private B b;

   public A() {
   }

   public A(B b) {
      this.b = b;
   }

   public B getB() {
      return b;
   }

   public void setB(B b) {
      this.b = b;
   }
}

public class B {
    private C c;

    public B() {
    }

    public B(C c) {
        this.c = c;
    }

    public void setC(C c) {
        this.c = c;
    }

    public C getC() {
        return c;
    }
}

public class C {
    private A a;

    public C() {
    }

    public C(A a) {
        this.a = a;
    }

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }
}

测试代码:

public class Main {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println(ac.getBean(A.class));
    }
}

构造器注入

xml配置

<bean id="A" class="A">
      <constructor-arg name="b" ref="B"/>
   </bean>

    <bean id="B" class="B" >
      <constructor-arg name="c" ref="C"/>
   </bean>

    <bean id="C" class="C" >
      <constructor-arg name="a" ref="A"/>
   </bean>

直接运行,发现报错了,说明Spring无法解决构造器注入循环依赖。

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'A' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'B' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'B' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'C' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'C' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'A' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'A': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:707)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:198)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
    at Main.main(Main.java:6)
...

通过报错

at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)

定位到resolveReference()代码。

@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
   try {
      Object bean;
      // 获取依赖的Bean引用名称,如A依赖B,那么这里ref就是B
      String refName = ref.getBeanName();
      refName = String.valueOf(doEvaluate(refName));
      // 如果是父容器中的引用,那么直接返回父容器中的指定对象
      if (ref.isToParent()) {
         if (this.beanFactory.getParentBeanFactory() == null) {
            throw new BeanCreationException(
                  this.beanDefinition.getResourceDescription(), this.beanName,
                  "Can't resolve reference to bean '" + refName +
                        "' in parent factory: no parent factory available");
         }
         bean = this.beanFactory.getParentBeanFactory().getBean(refName);
      }
      else {
         // 从当前容器中获取指定的bean引用
         bean = this.beanFactory.getBean(refName);
         // 将当前实例化对象依赖引用对象
         this.beanFactory.registerDependentBean(refName, this.beanName);
      }
      if (bean instanceof NullBean) {
         bean = null;
      }
      return bean;
   }
   catch (BeansException ex) {
      throw new BeanCreationException(
            this.beanDefinition.getResourceDescription(), this.beanName,
            "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
   }
}

再通过DEBUG定位到bean = this.beanFactory.getBean(refName);

@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}

// 真正实现向IOC容器获取Bean的地方,也就是触发依赖注入的地方
    @SuppressWarnings("unchecked")
    protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {

        String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        // 先从缓存中获取Bean,防止已经创建过的单例Bean重复创建
        Object sharedInstance = getSingleton(beanName);
        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 + "'");
                }
            }
            // 完成FactoryBean的相关处理
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            // 检查当前bean是否正在创建中
            // 类型为protoType的bean循环依赖,这里会报错
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            // 检查IOC容器中BeanDefinition是否存在,检查是否能从当前的BeanFactory中取得所需要的Bean。
            // 如果当前的工厂取不到,则委托父容器BeanFactory去寻找。
            // 如果父容器工厂也取不到,那么往上沿着继承关系继续委托父容器去寻找
            BeanFactory parentBeanFactory = getParentBeanFactory();
            // 如果父容器存在,并且当前容器中找不到指定bean的BeanDefinition
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                // 解析bean的原始名称
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    // Delegation to parent with explicit args.
                    // 委托父容器根据bean的原始名称和参数去寻找
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // No args -> delegate to standard getBean method.
                    // 委托父容器根据bean的原始名称和类型去寻找
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            // 创建的bean是否需要进行类型检查
            if (!typeCheckOnly) {
                // 标记bean已经被创建
                markBeanAsCreated(beanName);
            }

            try {
                // 根据bean名称获取BeanDefinition
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                // 获取当前bean的所有依赖bean,这里会触发一个getBean的递归使用,
                // 直到渠道一个没有任何依赖的Bean为止
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        try {
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // Create bean instance.
                // 创建单例bean
                if (mbd.isSingleton()) {
                    // 采用匿名内部类的方式,为依赖创建一个bean实例
                    // 构造器注入循环依赖时,循环一遍这里会报错
                    sharedInstance = getSingleton(beanName, () -> {
                        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);
                }

                // 创建prototype bean
                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                        // 在创建bean前会把beanName放入prototypesCurrentlyInCreation
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                // 创建除单例,原型以外的bean
                else {
                    String scopeName = mbd.getScope();
                    if (!StringUtils.hasLength(scopeName)) {
                        throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
                    }
                    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, () -> {
                            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.
        // 对创建的bean进行类型检查,如果没有问题,则返回这个新创建的bean
        // 这里bean已经包含了依赖关系
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }
            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;
    }

通过DEBUG后发现进过一轮A,B,C依赖创建后再创建依赖A时getSingleton()报错

if (mbd.isSingleton()) {
  // 采用匿名内部类的方式,为依赖创建一个bean实例
  sharedInstance = getSingleton(beanName, () -> {
    try {
      return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
      ...
    }
  });
  ...
}

再对getSingleton()进行DEBUG。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name 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 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<>();
         }
         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;
   }
}

发现beforeSingletonCreation(beanName);报错。

/** Names of beans that are currently in creation */
    private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));
            
 protected void beforeSingletonCreation(String beanName) {
        // 构造器注入在一轮循环后!this.singletonsCurrentlyInCreation.add(beanName)报错,
        // singletonsCurrentlyInCreation中bean已经存在了
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }

singletonsCurrentlyInCreation是一个set集合,每次创建bean前,都会对当前的bean进行记录。

循环依赖中:

  1. 创建A类bean,singletonsCurrentlyInCreation添加A,发现A类bean依赖B类bean,B类bean还没创建
  2. 于是去创建B类bean,singletonsCurrentlyInCreation添加B,发现B类bean依赖C类bean,C类bean还没创建
  3. 于是去创建C类bean,singletonsCurrentlyInCreation添加C,发现C类bean依赖A类bean,A类bean还没创建
  4. 于是继续去创建A类bean,当尝试往singletonsCurrentlyInCreation添加A的时候,因为第一步已经被添加了,表示正在被创建,所以添加失败,报错。

setter注入(单例)

xml配置:

<bean id="A" class="A">
  <property name="b" ref="B"/>
</bean>

<bean id="B" class="B" >
  <property name="c" ref="C"/>
</bean>

<bean id="C" class="C" >
  <property name="a" ref="A"/>
</bean>

运行发现没有报错,说明Spring帮忙解决了setter注入(单例)的循环依赖。

于是去探究和构造器注入有什么区别。

因为主要方法还是那个doGetBean(),所以在那边DEBUG。

发现一轮依赖后能从缓存中获取A类的bean了。

// 先从缓存中获取Bean,防止已经创建过的单例Bean重复创建
// setter注入(单例),一轮后sharedInstance不为null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
  if (logger.isDebugEnabled()) {
    if (isSingletonCurrentlyInCreation(beanName)) {
      ...
    }
    else {
      ...
    }
  }
  ...
}

而在构造器注入中从缓存中获取beanObject sharedInstance = getSingleton(beanName)一直是null,所以走得都是else创建bean的逻辑。

进入getSingleton()

/** Cache of singleton objects: bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of early singleton objects: bean name --> bean instance */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** Cache of singleton factories: bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

@Nullable
public Object getSingleton(String beanName) {
   return getSingleton(beanName, true);
}

@Nullable
    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) {
          // setter注入(单例),一轮后this.singletonFactories.get(beanName)能获取到创建bean的单例工厂
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

这就是有名的Spring三级缓存,先从一级缓存singletonObject获取bean,如果没有,那么去earlySingletonObject获取早期bean(还没进行包装处理的bean)。如果还是没有,那么去singletonFactories中获取创建早期bean的单例工厂。

而setter注入一轮后,singletonFactories 中可以获取到单例工厂,于是去寻找是何时往singletonFactories添加了A类的bean单例创建工厂。

通过used查找,发现只有这一个方法往singletonFactories添加单例工厂。

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);
      }
   }
}

在往上查找发现是doCreatBean()中调用了这个方法,而这个方法在createBean()被调用。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
        ...
        try {
      // 这里调用了doCreateBean
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isDebugEnabled()) {
                logger.debug("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            ...
        }
        catch (Throwable ex) {
            ...
        }
    }

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable 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);
   }
   Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
      mbd.resolvedTargetType = beanType;
   }

   // Allow post-processors to modify the merged bean definition.
   ...

   // 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");
      }
      // 存放beanName对应的单例工厂,这里调用了addSingletonFactory
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   ...
   // Register bean as disposable.
   ...

   return exposedObject;
}

createBean()doGetBean()中调用的地方经过构造器注入的追溯很清楚了。

if (mbd.isSingleton()) {
  // 采用匿名内部类的方式,为依赖创建一个bean实例
  sharedInstance = getSingleton(beanName, () -> {
    try {
      return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
      ...
    }
  });
  ...
}

也就是说在第一轮尝试创建bean实例的时候通过createBean()singletonFactories添加了单例工厂。

可是构造器注入也同样走的是这套代码,为什么构造器注入中没有往singletonFactories添加单例工厂呢?

应该是中间哪一步断了,于是再对doCreateBean进行构造器注入的DEBUG,发现到instanceWrapper = createBeanInstance(beanName, mbd, args)抛出BeanCreationException异常。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   ...
   if (instanceWrapper == null) {
     // 构造器注入这里抛出异常
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   ...

   // 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");
      }
      // 存放beanName对应的单例工厂,这里调用了addSingletonFactory
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   ...

   return exposedObject;
}

createBeanInstance():

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // Make sure bean class is actually resolved at this point.
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
   }

   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   if (mbd.getFactoryMethodName() != null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // Shortcut when re-creating the same bean...
   boolean resolved = false;
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   if (resolved) {
      if (autowireNecessary) {
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         return instantiateBean(beanName, mbd);
      }
   }

   // Candidate constructors for autowiring?
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // No special handling: simply use no-arg constructor.
   // 调用无参构造函数创建bean实例
   return instantiateBean(beanName, mbd);
}

再进行DEBUG后发现最后一行return instantiateBean(beanName, mbd);抛出了错误。其实从注释很清楚,这是依靠无参构造方法来实例化Bean,而构造器注入要求的是有参数的构造方法,所以这里抛出错误也算情理之中。

setter注入(原型)

xml代码:

<bean id="A" class="A" scope="prototype">
   <constructor-arg name="b" ref="B"/>
</bean>

<bean id="B" class="B" scope="prototype">
        <constructor-arg name="c" ref="C"/>
    </bean>

<bean id="C" class="C" scope="prototype">
        <constructor-arg name="a" ref="A"/>
    </bean>

还是去运行代码,发现报错了,Spring没法解决setter注入(原型)方式的循环依赖。

于是再对doGetBean()DEBUG,发现这里抛出了错误。

// 检查当前bean是否正在创建中
if (isPrototypeCurrentlyInCreation(beanName)) {
   throw new BeanCurrentlyInCreationException(beanName);
}

private final ThreadLocal<Object> prototypesCurrentlyInCreation =
            new NamedThreadLocal<>("Prototype beans currently in creation");

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
        // 每次在创建bean前,先判断当前bean是否正在创建中
        Object curVal = this.prototypesCurrentlyInCreation.get();
        return (curVal != null &&
                (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
    }

在创建bean前判断当前bean是否正在被创建,虽然因为多线程用了ThreadLocal拿来记录当前正在创建的bean,但是应该和构造器注入判断出是循环依赖的原因一样。

找到是beforePrototypeCreation()中往prototypesCurrentlyInCreation添加了当前的bean。

protected void beforePrototypeCreation(String beanName) {
   Object curVal = this.prototypesCurrentlyInCreation.get();
   if (curVal == null) {
      this.prototypesCurrentlyInCreation.set(beanName);
   }
   else if (curVal instanceof String) {
      Set<String> beanNameSet = new HashSet<>(2);
      beanNameSet.add((String) curVal);
      beanNameSet.add(beanName);
      this.prototypesCurrentlyInCreation.set(beanNameSet);
   }
   else {
      Set<String> beanNameSet = (Set<String>) curVal;
      beanNameSet.add(beanName);
   }
}

beforePrototypeCreation()doGetBean()中调用位置。

// 创建prototype bean
else if (mbd.isPrototype()) {
   // It's a prototype -> create a new instance.
   Object prototypeInstance = null;
   try {
      // 这里,在创建bean前会把beanName放入prototypesCurrentlyInCreation
      beforePrototypeCreation(beanName);
      prototypeInstance = createBean(beanName, mbd, args);
   }
   finally {
      afterPrototypeCreation(beanName);
   }
   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

总结

  1. Spring会先从三级缓存中获取bean,如果没有,再尝试创建bean。
  2. 创建有依赖的bean是一个递归过程,Spring会把每一个正在创建的bean名称放入set中,依靠判断set中是否存在判断是否存在循环依赖。
  3. 构造器注入和setter注入(单例)一个Spring能解决,一个不能解决的原因是,setter注入依靠无参构造方法可以创建一个bean实例,于是Spring把单例工厂放入第三级缓存。等一轮依赖过后就可以从第三级缓存中获取这个单例工厂,靠工厂可以创建bean。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容