Spring 源码阅读笔记(四)

Spring 源码阅读笔记(四)

前篇导航

Spring 源码阅读笔记(一)
Spring 源码阅读笔记(二)
Spring 源码阅读笔记(三)

前景回顾

在上一章节中,读完了obtainFreshBeanFactory()方法中的大部分代码,最终剩余factory中registerBeanDefinition方法太过复杂,当时先跳过了,由这篇文章补全。

obtainFreshBeanFactory方法目前读下来,起到的作用很简单,创建了一个DefaultListableBeanFactory,然后像BeanFactory中放入BeanDefinition。

正式开始

我们这次重点关注的方法是在DefaultListableBeanFactory的registerBeanDefinition方法,先来看一下这段代码。

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");

   if (beanDefinition instanceof AbstractBeanDefinition abd) {
      try {
         abd.validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   if (existingDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
         throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         if (logger.isInfoEnabled()) {
            logger.info("Overriding user-defined bean definition for bean '" + beanName +
                  "' with a framework-generated bean definition: replacing [" +
                  existingDefinition + "] with [" + beanDefinition + "]");
         }
      }
      else if (!beanDefinition.equals(existingDefinition)) {
         if (logger.isDebugEnabled()) {
            logger.debug("Overriding bean definition for bean '" + beanName +
                  "' with a different definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      else {
         if (logger.isTraceEnabled()) {
            logger.trace("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      if (isAlias(beanName)) {
         if (!isAllowBeanDefinitionOverriding()) {
            String aliasedName = canonicalName(beanName);
            if (containsBeanDefinition(aliasedName)) {  // alias for existing bean definition
               throw new BeanDefinitionOverrideException(
                     beanName, beanDefinition, getBeanDefinition(aliasedName));
            }
            else {  // alias pointing to non-existing bean definition
               throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                     "Cannot register bean definition for bean '" + beanName +
                     "' since there is already an alias for bean '" + aliasedName + "' bound.");
            }
         }
         else {
            removeAlias(beanName);
         }
      }
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            removeManualSingletonName(beanName);
         }
      }
      else {
         // Still in startup registration phase
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
   else if (isConfigurationFrozen()) {
      clearByTypeCache();
   }
}
复制代码

粗略的看下来呢,这段代码中有很多的if判断,这将减轻我们阅读工作量,因为每当进入一个判断分支,那么将意味着另一个分支的代码即是不用看的。

接下来先看一下这个方法入参

  1. String beanName
  2. BeanDefinition beanDefinition

在上一章节中有读到,DefaultBeanDefinitionDocumentReader中的processBeanDefinition其中有这样的一段代码

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
   BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
复制代码

感兴趣的可以代码追进去看一下,是根据Xml去生成对应BeanDefinitionHolder,至于Bean Definition就是从Holder中获取的了。提一嘴因为后面会用到,这里创建出的BeanDefinition为GenericBeanDefinition,这里我们在类关系图中维护一下,截出一小段。

image.png

BeanDefinition的创建过程

我在读后面的registerBeanDefinition方法时,在涉及到BeanDefinition时还是有些吃力的,所以这里要补一下,BeanDefinition是怎么创建出来的。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      // ... 其他的代码和创建BeanDefinition没有关系,这里跳过
   }
}

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
   return parseBeanDefinitionElement(ele, null);
}

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
   String id = ele.getAttribute(ID_ATTRIBUTE);
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

   List<String> aliases = new ArrayList<>();
   if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }

   String beanName = id;
   if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isTraceEnabled()) {
         logger.trace("No XML 'id' specified - using '" + beanName +
               "' as bean name and " + aliases + " as aliases");
      }
   }

   if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
   }

   AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {
      if (!StringUtils.hasText(beanName)) {
         try {
            if (containingBean != null) {
               beanName = BeanDefinitionReaderUtils.generateBeanName(
                     beanDefinition, this.readerContext.getRegistry(), true);
            }
            else {
               beanName = this.readerContext.generateBeanName(beanDefinition);
               // Register an alias for the plain bean class name, if still possible,
               // if the generator returned the class name plus a suffix.
               // This is expected for Spring 1.2/2.0 backwards compatibility.
               // 如果生成器返回类名加上后缀,
               // 则为普通 bean 类名注册一个别名(如果仍然可能)。 
               // 这是 Spring 1.2/2.0 向后兼容性所期望的。
               String beanClassName = beanDefinition.getBeanClassName();
               if (beanClassName != null &&
                     beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                     !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                  aliases.add(beanClassName);
               }
            }
            if (logger.isTraceEnabled()) {
               logger.trace("Neither XML 'id' nor 'name' specified - " +
                     "using generated bean name [" + beanName + "]");
            }
         }
         catch (Exception ex) {
            error(ex.getMessage(), ele);
            return null;
         }
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}
复制代码

从这里可以看到了,上方贴出的代码中,我们所关注的只有BeanDefinition的创建方法,那可以看出,parseBeanDefinitionElement(ele, beanName, containingBean)这一段就是了,那么看一下他的代码是怎么样的。

@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {

   this.parseState.push(new BeanEntry(beanName));

   String className = null;
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
   }
   String parent = null;
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }

   try {
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);

      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

      parseMetaElements(ele, bd);
      parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

      parseConstructorArgElements(ele, bd);
      parsePropertyElements(ele, bd);
      parseQualifierElements(ele, bd);

      bd.setResource(this.readerContext.getResource());
      bd.setSource(extractSource(ele));

      return bd;
   }
   catch (ClassNotFoundException ex) {
      error("Bean class [" + className + "] not found", ele, ex);
   }
   catch (NoClassDefFoundError err) {
      error("Class that bean class [" + className + "] depends on not found", ele, err);
   }
   catch (Throwable ex) {
      error("Unexpected failure during bean definition parsing", ele, ex);
   }
   finally {
      this.parseState.pop();
   }

   return null;
}
复制代码

这段代码需要拆开看他的代码,条理更清晰些。

第一段创建BeanDefinition核心方法的代码

// 这里是一个转换的状态,是一个Set
this.parseState.push(new BeanEntry(beanName));

String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
   className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
   parent = ele.getAttribute(PARENT_ATTRIBUTE)zh;
}
复制代码

上方代码中判断了xml中有没有设置了class和parent属性,如果设置了,赋值给局部变量。
这里重要的一个点,获取了className,因为class属性,肯定会设置的。

第二段创建BeanDefinition核心方法的代码

AbstractBeanDefinition bd = createBeanDefinition(className, parent);

protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
      throws ClassNotFoundException {

   return BeanDefinitionReaderUtils.createBeanDefinition(
         parentName, className, this.readerContext.getBeanClassLoader());
}

public static AbstractBeanDefinition createBeanDefinition(
      @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

   GenericBeanDefinition bd = new GenericBeanDefinition();
   bd.setParentName(parentName);
   if (className != null) {
      if (classLoader != null) {
         bd.setBeanClass(ClassUtils.forName(className, classLoader));
      }
      else {
         bd.setBeanClassName(className);
      }
   }
   return bd;
}
复制代码

从这里就看到了,BeanDefinition是new了一个GenericBeanDefinition。由于我们这里传入的ClassLoader为空,所以此代码中,就只设置了一个BeanClass属性。随后完成了第一阶段创建BeanDefinition。


parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
      @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

   if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
      error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
   }
   else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
      bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
   }
   else if (containingBean != null) {
      // Take default from containing bean in case of an inner bean definition.
      bd.setScope(containingBean.getScope());
   }

   if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
      bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
   }

   String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
   if (isDefaultValue(lazyInit)) {
      lazyInit = this.defaults.getLazyInit();
   }
   bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

   String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
   bd.setAutowireMode(getAutowireMode(autowire));

   if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
      String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
      bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
   }

   String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
   if (isDefaultValue(autowireCandidate)) {
      String candidatePattern = this.defaults.getAutowireCandidates();
      if (candidatePattern != null) {
         String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
         bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
      }
   }
   else {
      bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
   }

   if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
      bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
   }

   if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
      String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
      bd.setInitMethodName(initMethodName);
   }
   else if (this.defaults.getInitMethod() != null) {
      bd.setInitMethodName(this.defaults.getInitMethod());
      bd.setEnforceInitMethod(false);
   }

   if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
      String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
      bd.setDestroyMethodName(destroyMethodName);
   }
   else if (this.defaults.getDestroyMethod() != null) {
      bd.setDestroyMethodName(this.defaults.getDestroyMethod());
      bd.setEnforceDestroyMethod(false);
   }

   if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
      bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
   }
   if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
      bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
   }

   return bd;
}
复制代码

上面的方法具体设置了一些什么属性,想了解的可以了解一下,这个上面具体做的就是根据xml中的一些属性,设置BeanDefinition中的属性。

parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

arseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
复制代码

下面这一段代码,都是根据xml去设置一些属性,没必要去了解xml的读写过程,具体标签是什么意思,知道一下就好了。 BeanDefinition的创建就到这里就结束了,下面进入Register的过程。

registerBeanDefinition 代码解读

此方法代码过长,逻辑判断多且复杂,这里我们抽出来分段的看。

第一段代码

if (beanDefinition instanceof AbstractBeanDefinition abd) {
   try {
      abd.validate();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
            "Validation of bean definition failed", ex);
   }
}
复制代码

这里第一段代码,判断BeanDefinition的继承关系,继承自AbstractBeanDefinition,调用validate方法要去检验一些什么参数,看一下代码。

public void validate() throws BeanDefinitionValidationException {
   if (hasMethodOverrides() && getFactoryMethodName() != null) {
      throw new BeanDefinitionValidationException(
            "Cannot combine factory method with container-generated method overrides: " +
            "the factory method must create the concrete bean instance.");
   }
   if (hasBeanClass()) {
      prepareMethodOverrides();
   }
}
复制代码

第一个if不会进去,因为当前没有方法冲写,第二个方法也不会进入,因为我们塞入的beanclass是className,String类型的,并不是Class类。所以这里是执行了个寂寞。

第二段代码

因为由于

BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
    // ....
}
else {
   if (isAlias(beanName)) {
      // .. 不会走这里
   }
   if (hasBeanCreationStarted()) {
      // .. 不会走这里
   }
   else {
      // Still in startup registration phase
      this.beanDefinitionMap.put(beanName, beanDefinition);
      this.beanDefinitionNames.add(beanName);
      removeManualSingletonName(beanName);
   }
   this.frozenBeanDefinitionNames = null;
}
复制代码

从第一行的代码中,可以看出beanDefinitionMap就是最终存放BeanDefinition的容器了。

在第二个if中isAlias(beanName),判断为false,因为beanName并不是别名。

第三个if中hasBeanCreationStarted(),这里判断也为false,具体原因因为我们这个是第一次创建,BeanFactory中有一个属性alreadyCreated是空的。

然后在else中,向beanDefinitionMap、beanDefinitionNames赋值。

告一段落

到这里了,注册BeanDefinition的方法解读就到这里结束了,在下一篇文章中将会继续探索Refresh方法的流程代码,那么到这里为止的类图在下面贴出。

image.png

结束语

写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。

image.png

猜你喜欢

转载自juejin.im/post/7077217239572676639