追溯IOC循环依赖处理

2021-07-31  本文已影响0人  修伊Dal

追溯IOC循环依赖处理

前言

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

image-20210730200115421.png

而Spring中循环依赖有三种:

本文主要是对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。
上一篇下一篇

猜你喜欢

热点阅读