Spring类解析[02] BeanFactory

140 阅读7分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

前言

在对Spring启动流程的解析中,可以了解到BeanFactory是Spring的一个核心组件。在启动流程中使用的BeanFactory实现为DefaultListableBeanFactory,其继承树如下图所示:

www.processon.com/view/link/6…

实际上,虽然上下文对象ApplicationContext实现了BeanFactory接口,但对于BeanFactory的使用是通过组合而非继承关系实现的,相关功能是通过其设置的DefaultListableBeanFactory来进行的。

因此这里就围绕DefaultListableBeanFactory进行解析。

类解析

需要预先知道使用代表信息的类

第一个就是BeanDefinition了,这个类代表的信息是一个bean的身份证,记录了创建一个bean时所需要的相关信息。

第二个是BeanDefinitionHolder,实际上算是BeanDefinition的一个门面,附带了名字以及别名相关的信息,略显不重要,类上注释这么交代:

 If you don't care about BeanNameAware and the like,
 * registering RootBeanDefinition or ChildBeanDefinition is good enough.

注释

先来看看类上的注释,Spring的类注释都写得很详细:

 Spring's default implementation of the {@link ConfigurableListableBeanFactory}
 and {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
 based on bean definition metadata, extensible through post-processors.
 ​
 <p>Typical usage is registering all bean definitions first (possibly read
 from a bean definition file), before accessing beans. Bean lookup by name
 is therefore an inexpensive operation in a local bean definition table,
 operating on pre-resolved bean definition metadata objects.
 ​
 <p>Note that readers for specific bean definition formats are typically
 implemented separately rather than as bean factory subclasses: see for example
 {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
 ​
 <p>For an alternative implementation of the
 {@link org.springframework.beans.factory.ListableBeanFactory} interface,
 have a look at {@link StaticListableBeanFactory}, which manages existing
 bean instances rather than creating new ones based on bean definitions.

大致意思讲的是:

  • 大致用途:DefaultListableBeanFactory是Spring中对于ConfigurableListableBeanFactoryBeanDefinitionRegistry的默认实现,一个基于beanDefinition元数据,支持通过post处理器扩展的完整beanFactory

  • 使用案例:典型的使用方法是:

    • 在触达到bean之前,先注册所有BeanDeifinition(可能是从beanDefinition文件)

    在预先初始化的BD元数据对象的本地BD表中,通过名字查找bean是一个耗费小的操作。

  • 读取BD注意事项:

    • 特殊读取BD格式的reader是被单独实现的,而不是作为beanFactory的子类,例子:XmlBeanDefinitionReader
  • 平级替代:一个可替换的实现的接口是ListableBeanFactory,例子是StaticListableBeanFactory,这个实现类管理的是已存在的bean实例,而非通过BD创建一个新的bean。

根据注释,大概能了解到的信息如下:

  • DefaultListableBeanFactory在Spring中的地位其实相当之高,是一个默认的终端实现,也就是说在非特殊的流程中一般见到的BeanFactory就是这个了。
  • DefaultListableBeanFactory的一个核心是BD的注册和通过BD构造新实例,因此源码的阅读上重点关注这部分的内容。

流程解析 - 1.BD注册

这块主要是registerBeanDefinition,在之前额外信息【1】中已经说过了,此处不再赘述。

需要注意的一点是,这个接口是registerBeanDefinition,实际上并不是BeanFactory的接口实现,而是对BeanDefinitionRegistry的接口实现。

这一步中留意一下注释里提到的本地注册表,实质上是一堆ConcurrentHashMap构成的。

需要注意的是,这里的注册表和bean实例没关系,存放的其实是BeanDefinition。

流程解析 - 2.bean获取

到了获取Bean,根据名称很容易能定位到getBean的接口。

 @Override
 public <T> T getBean(Class<T> requiredType) throws BeansException {
    return getBean(requiredType, (Object[]) null);
 }
 ​
 @SuppressWarnings("unchecked")
 @Override
 public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
    Assert.notNull(requiredType, "Required type must not be null");
    Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
    if (resolved == null) {
       throw new NoSuchBeanDefinitionException(requiredType);
    }
    return (T) resolved;
 }

看参数就能知道是通过class来获取bean的,这里也符合前面通过beanFactory中,存储BD的逻辑:名字为key,BD为value。具体的工作到了resolveBean里,接下来看看这个方法:

 @Nullable
 private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
    NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
    if (namedBean != null) {
       return namedBean.getBeanInstance();
    }
    BeanFactory parent = getParentBeanFactory();
    if (parent instanceof DefaultListableBeanFactory) {
       return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
    }
    else if (parent != null) {
       ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
       if (args != null) {
          return parentProvider.getObject(args);
       }
       else {
          return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
       }
    }
    return null;
 }

分解一下:

  • resolveNamedBean
  • parentBeanFactory
  • ObjectProvider

resolveNamedBean

在看代码之前需要提前知道一下这个ResolvableType是何方神圣:

在上一步中,我们是通过一下方法来获取这个对象的:

 public static ResolvableType forRawClass(@Nullable Class<?> clazz) {
    return new ResolvableType(clazz) {
       @Override
       public ResolvableType[] getGenerics() {
          return EMPTY_TYPES_ARRAY;
       }
       @Override
       public boolean isAssignableFrom(Class<?> other) {
          return (clazz == null || ClassUtils.isAssignable(clazz, other));
       }
       @Override
       public boolean isAssignableFrom(ResolvableType other) {
          Class<?> otherClass = other.resolve();
          return (otherClass != null && (clazz == null || ClassUtils.isAssignable(clazz, otherClass)));
       }
    };
 }

就当作一个带着一些判别方法的class代理对象就可以了。

接下来看看具体的方法:

 private <T> NamedBeanHolder<T> resolveNamedBean(
       ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
 ​
    Assert.notNull(requiredType, "Required type must not be null");
     //这个方法调用链很深,其实简单点来说就是通过class对象获取bean名称
    String[] candidateNames = getBeanNamesForType(requiredType);
 ​
     //从这里开始就是通过上面取得的bean名称,来获取实例了
     //这里就会根据bean名称以及beanDefinition的相关属性,来获取可能需要的所有bean
    if (candidateNames.length > 1) {
       List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
       for (String beanName : candidateNames) {
          if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
             autowireCandidates.add(beanName);
          }
       }
       if (!autowireCandidates.isEmpty()) {
          candidateNames = StringUtils.toStringArray(autowireCandidates);
       }
    }
 ​
    if (candidateNames.length == 1) {
       return resolveNamedBean(candidateNames[0], requiredType, args);
    }
    else if (candidateNames.length > 1) {
       Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
       for (String beanName : candidateNames) {
           //在这里就能看到:如果有这个单例bean,那么就获取这个单例bean
          if (containsSingleton(beanName) && args == null) {
             Object beanInstance = getBean(beanName);
             candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
          }
          else {
             candidates.put(beanName, getType(beanName));
          }
       }
       String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
       if (candidateName == null) {
          candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
       }
       if (candidateName != null) {
          Object beanInstance = candidates.get(candidateName);
          if (beanInstance == null) {
             return null;
          }
          if (beanInstance instanceof Class) {
             return resolveNamedBean(candidateName, requiredType, args);
          }
          return new NamedBeanHolder<>(candidateName, (T) beanInstance);
       }
       if (!nonUniqueAsNull) {
          throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
       }
    }
 ​
    return null;
 }

大致浏览一下这个方法,其实做的事情是这样的:

  • 首先,通过class,获取bean名称

  • 通过这些bean名称,来获取一个备选name组合(如果有autowired的BD,就只取这些,否则全部取)

  • 经过上面的步骤,在来进行分析:

    • 如果只剩一个了,那么就去获取bean
    • 如果还剩很多,那就先获取bean,根据优先级来决定最后剩下的bean名称,最后还是获取bean

在这里又兜兜转转回到了getBean,但这个getBean实际上就到了AbstractBeanFactory里面,这里就是获取bean最后的关键步骤了。

来看AbstractBeanFactory里的这个方法:

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

doGetBean方法就一百多行,就不一次性贴出,来分部解析:

doGetBean【1】 - 获取bean名称并尝试缓存获取

在方法的前面会进行一个名称的获取:

 String beanName = transformedBeanName(name);

可能会有疑问了:不是有名字了吗为什么还要获取一遍?

  • 其实是因为Spring是允许bean有别名的,因此需要先看看是否有已经根据别名初始化了的bean。

接下来就是获取单例bean:

 Object sharedInstance = getSingleton(beanName);

这里的获取单例,是DefaultSingletonBeanRegistry里的方法。

  • Spring中经常出现的三级缓存,就在这个类中了。

来看看这里的方法:

 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
       singletonObject = this.earlySingletonObjects.get(beanName);
       if (singletonObject == null && allowEarlyReference) {
          synchronized (this.singletonObjects) {
             // Consistent creation of early reference within full singleton lock
             singletonObject = this.singletonObjects.get(beanName);
             if (singletonObject == null) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null) {
                   ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                   if (singletonFactory != null) {
                      singletonObject = singletonFactory.getObject();
                      this.earlySingletonObjects.put(beanName, singletonObject);
                      this.singletonFactories.remove(beanName);
                   }
                }
             }
          }
       }
    }
    return singletonObject;
 }

这里会在这三个缓存中来尝试获取bean:

  • singletonObjects
  • earlySingletonObjects
  • singletonFactories

这里能看到,三级缓存也遵守了Spring中和bean相关的一致定义:相关的缓存都是使用bean名称作为key的。

在这里是不太清楚前两个缓存有啥区别,不过第三个缓存的功能还是比较清楚的:

  • 事实上这里存放的是来制造early单例的工厂。

关于这部分的内容,我们就放到BeanRegistry里来解析,这里就先往下看流程。

doGetBean【2】 - 成功获取缓存

如果上一步获取到了缓存,那么接下来执行的就是这部分的代码(上面传入的args是null):

 if (sharedInstance != null && args == null) {
    if (logger.isTraceEnabled()) {
       if (isSingletonCurrentlyInCreation(beanName)) {
          logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                "' that is not fully initialized yet - a consequence of a circular reference");
       }
       else {
          logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
       }
    }
    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 }

实际上就到这个getObjectForBeanInstance了:

 protected Object getObjectForBeanInstance(
       Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
 ​
    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    if (BeanFactoryUtils.isFactoryDereference(name)) {
       if (beanInstance instanceof NullBean) {
          return beanInstance;
       }
       if (!(beanInstance instanceof FactoryBean)) {
          throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
       }
       if (mbd != null) {
          mbd.isFactoryBean = true;
       }
       return beanInstance;
    }
 ​
    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    if (!(beanInstance instanceof FactoryBean)) {
       return beanInstance;
    }
 ​
    Object object = null;
    if (mbd != null) {
       mbd.isFactoryBean = true;
    }
    else {
       object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
       // Return bean instance from factory.
       FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
       // Caches object obtained from FactoryBean if it is a singleton.
       if (mbd == null && containsBeanDefinition(beanName)) {
          mbd = getMergedLocalBeanDefinition(beanName);
       }
       boolean synthetic = (mbd != null && mbd.isSynthetic());
       object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
 }

这里的注解里出现了一个也是Spring中高频被问到的类:factoryBean,我们也放到后面一并进行解析,这里只需要知道这个FactoryBean代表的其实就是把Factory封装成bean。

流程其实想要做的事情很简单,如果外部获取的是FactoryBean,就判断后返回;如果不是,就尝试通过这个FactoryBean,来获取调用方期望获得的bean。

doGetBean【3】 - 获取缓存失败

如果在【1】中获取单例bean失败,或者外部传入的args不为null,那么此时会执行下面的代码:

 else {
    // Fail if we're already creating this bean instance:
    // We're assumably within a circular reference.
    if (isPrototypeCurrentlyInCreation(beanName)) {
       throw new BeanCurrentlyInCreationException(beanName);
    }
 ​
    // Check if bean definition exists in this factory.
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
       // Not found -> check parent.
       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.
          return (T) parentBeanFactory.getBean(nameToLookup, args);
       }
       else if (requiredType != null) {
          // No args -> delegate to standard getBean method.
          return parentBeanFactory.getBean(nameToLookup, requiredType);
       }
       else {
          return (T) parentBeanFactory.getBean(nameToLookup);
       }
    }
 ​
    if (!typeCheckOnly) {
       markBeanAsCreated(beanName);
    }
 ​
    StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
          .tag("beanName", name);
    try {
       if (requiredType != null) {
          beanCreation.tag("beanType", requiredType::toString);
       }
       RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
       checkMergedBeanDefinition(mbd, beanName, args);
 ​
       // Guarantee initialization of beans that the current bean depends on.
       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.
       if (mbd.isSingleton()) {
          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;
             }
          });
          beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
       }
 ​
       else if (mbd.isPrototype()) {
          // It's a prototype -> create a new instance.
          Object prototypeInstance = null;
          try {
             beforePrototypeCreation(beanName);
             prototypeInstance = createBean(beanName, mbd, args);
          }
          finally {
             afterPrototypeCreation(beanName);
          }
          beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
       }
 ​
       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);
                }
             });
             beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
          }
          catch (IllegalStateException ex) {
             throw new ScopeNotActiveException(beanName, scopeName, ex);
          }
       }
    }
    catch (BeansException ex) {
       beanCreation.tag("exception", ex.getClass().toString());
       beanCreation.tag("message", String.valueOf(ex.getMessage()));
       cleanupAfterBeanCreationFailure(beanName);
       throw ex;
    }
    finally {
       beanCreation.end();
    }
 }

配置相关

  • addBeanPostProcessor
  • ignoreDependencyInterface

附录:遇到的相关接口

刷新上下文

setBeanExpressionResolver

addPropertyEditorRegistrar

addBeanPostProcessor

ignoreDependencyInterface

registerResolvableDependency

setTempClassLoader

registerSingleton

containsLocalBean