【挑战 Spring】—– Spring IOC 源码调试三之loadBeanDefinitions

674 阅读11分钟

前言

当你凝视黑夜的时候,黑夜也在凝视着你!日日当精进,干就完了!上篇Spring IOC 源码调试二的进度,进行到了重点的AbstractBeanDefinitionReaderloadBeanDefinitions方法**,那这一篇接着进行。原创纯手打!实属不易!求赞!求关注!我不会因为您的不支持而低迷,但是有了您的支持我会变的亢奋!

项目结构

这是调试代码

开始调试

(重点)1.执行AbstractBeanDefinitionReaderloadBeanDefinitions(String location, @Nullable Set actualResources)

该方法中主要操作有:

  1. ResourceLoader resourceLoader = getResourceLoader():获取一个ResourceLoader(资源加载器)对象

    此时获取到的ResourceLoader具体实现类是ClassPathXmlApplicationContext对象,详情请看Spring IOC 源码调试二2-5部分的第3个操作。

  2. int count = loadBeanDefinitions(resources):继续调用XmlBeanDefinitionReaderloadBeanDefinitions(Resource... resources)方法。此时的this对象是XmlBeanDefinitionReader

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
   //初始化 XmlBeanDefinitionReader 时 设置了 setResourceLoader(this)
   ResourceLoader resourceLoader = getResourceLoader();
   if (resourceLoader == null) {
      throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" +    												location + "]: no ResourceLoader available");
   }
   if (resourceLoader instanceof ResourcePatternResolver) {
      // Resource pattern matching available.
      try {
         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
         // 进一步调用 XmlBeanDefinitionReader的loadBeanDefinitions(Resource... resources)方法
          int count = loadBeanDefinitions(resources);
         if (actualResources != null) {
            Collections.addAll(actualResources, resources);
         }
         if (logger.isTraceEnabled()) {
            logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
         }
         return count;
      }
      catch (IOException ex) {
         throw new BeanDefinitionStoreException(
               "Could not resolve bean definition resource pattern [" + location + "]", ex);
      }
   }
   else {
      // Can only load single resources by absolute URL.
      Resource resource = resourceLoader.getResource(location);
      int count = loadBeanDefinitions(resource);
      if (actualResources != null) {
         actualResources.add(resource);
      }
      if (logger.isTraceEnabled()) {
         logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
      }
      return count;
   }
}

(重点)2.执行XmlBeanDefinitionReaderloadBeanDefinitions(Resource... resources)方法

看下面代码,该方法中是对每个资源逐一解析的,但是返回值是总的bean的个数。很无奈又是层层调用XmlBeanDefinitionReaderloadBeanDefinitions重载方法,调用过程中有一个逻辑是把参数Resource对象转换成了EncodeResource对象,并且最后调用到XmlBeanDefinitionReaderloadBeanDefinitions(EncodedResource encodedResource)方法

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
   Assert.notNull(resources, "Resource array must not be null");
   int count = 0;
   for (Resource resource : resources) {
      // 加载每个资源的 bean 的个数
      count += loadBeanDefinitions(resource);
   }
    // 返回总共 bean 的个数
   return count;
}

3.执行XmlBeanDefinitionReaderloadBeanDefinitions(EncodedResource encodedResource)方法

这个方法主要作用我认为就是获取到资源的输入流。重点是将输入流作为参数传入XmlBeanDefinitionReaderdoLoadBeanDefinitions(InputSource inputSource, Resource resource)方法中

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
   Assert.notNull(encodedResource, "EncodedResource must not be null");
   if (logger.isTraceEnabled()) {
      logger.trace("Loading XML bean definitions from " + encodedResource);
   }

   Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
   if (currentResources == null) {
      currentResources = new HashSet<>(4);
      this.resourcesCurrentlyBeingLoaded.set(currentResources);
   }
   if (!currentResources.add(encodedResource)) {
      throw new BeanDefinitionStoreException(
            "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
   }
   try {
       // 得到资源的输入流
      InputStream inputStream = encodedResource.getResource().getInputStream();
      try {
         InputSource inputSource = new InputSource(inputStream);
         if (encodedResource.getEncoding() != null) {
            inputSource.setEncoding(encodedResource.getEncoding());
         }
         // 真正 解析 XML 文件方法
         return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
      }
      finally {
         inputStream.close();
      }
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(
            "IOException parsing XML document from " + encodedResource.getResource(), ex);
   }
   finally {
      currentResources.remove(encodedResource);
      if (currentResources.isEmpty()) {
         this.resourcesCurrentlyBeingLoaded.remove();
      }
   }
}

4.(重点中的重点)执行XmlBeanDefinitionReaderdoLoadBeanDefinitions(InputSource inputSource, Resource resource)方法

该方法主要就两个操作:

  1. Document doc = doLoadDocument(inputSource, resource);:将xml文件解析为Document对象
  2. int count = registerBeanDefinitions(doc, resource):注册Beandefinition到容器(DefaultListableBeanFatory)中
/**将 xml文件  装载为  BeanDefinition
 */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {

   try {
      Document doc = doLoadDocument(inputSource, resource);
      int count = registerBeanDefinitions(doc, resource);
      if (logger.isDebugEnabled()) {
         logger.debug("Loaded " + count + " bean definitions from " + resource);
      }
      return count;
   }
   catch (BeanDefinitionStoreException ex) {
      throw ex;
   }
   catch (SAXParseException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
            "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
   }
   catch (SAXException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
            "XML document from " + resource + " is invalid", ex);
   }
   catch (ParserConfigurationException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "Parser configuration exception parsing XML from " + resource, ex);
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "IOException parsing XML document from " + resource, ex);
   }
   catch (Throwable ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "Unexpected exception parsing XML document from " + resource, ex);
   }
}

4-1Document doc = doLoadDocument(inputSource, resource)

此时的this对象依然为XmlBeanDefinitionReader对象,所以会执行XmlBeanDefinitionReaderdoLoadDocument(InputSource inputSource, Resource resource)方法,代码如下:

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
   return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
         getValidationModeForResource(resource), isNamespaceAware());
}

代码执行的逻辑:

  1. 首先在XmlBeanDefinitionReader对象中维护了一个private DocumentLoader documentLoader = new DefaultDocumentLoader();属性
  2. 执行DefaultDocumentLoaderloadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware)方法
  3. 最后调用到DocumentBuilderImplparse(InputSource is)方法,最后执行DOM解析,返回Document对象
  4. 由于DOM解析不是重点此处不进行深度跟踪。

得到xml文件的Document对象后作为参数传给:XmlBeanDefinitionReader对象的registerBeanDefinitions(doc, resource)方法

4-2执行:XmlBeanDefinitionReader对象的registerBeanDefinitions(Document doc, Resource resource)方法

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 获取一个`DefaultBeanDefinitionDocumentReader`对象
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    // 获取 注册Beandefinition之前 Beandefinition的数量
   int countBefore = getRegistry().getBeanDefinitionCount();
    // 注册 BeanDefinition
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

该方法中主要逻辑有:

4-2-1BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader()得到一个BeanDefinitionDocumentReader对象,真正的实现类是DefaultBeanDefinitionDocumentReader
4-2-2int countBefore = getRegistry().getBeanDefinitionCount();:获取 注册Beandefinition之前 Beandefinition的数量
  • 此时this对象为:XmlBeanDefinitionReader对象,调用getRegistry()方法时是调用父类AbstractBeanDefinitionReadergetRegistry()方法。
  • Spring IOC 源码调试二2-5部分的第一个操作在实例化:XmlBeanDefinitionReader对象的时候把DefaultListableBeanFactory最为参数传给了:XmlBeanDefinitionReader的构造参数,而DefaultListableBeanFactory对象又实现了BeanDefinitionRegistry,所以调用AbstractBeanDefinitionReadergetRegistry()方法得到的对象是DefaultListableBeanFactory
  • DefaultListableBeanFactorygetBeanDefinitionCount()方法就是获取beanDefinitionMap(Bean元数据信息集合)中的个数
4-2-3 documentReader.registerBeanDefinitions(doc, createReaderContext(resource));:注册 BeanDefinition
4-2-3.1该方法中参数中有一个逻辑:createReaderContext(resource):我理解为构造:XmlBeanDefinitionReader对象的应用上下文

大概意思就是把:XmlBeanDefinitionReader包装一下变成XmlReaderContext对象

public XmlReaderContext createReaderContext(Resource resource) {
   return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
         this.sourceExtractor, this, getNamespaceHandlerResolver());
}
4-2-3.2 (this对象变化)进入到DefaultBeanDefinitionDocumentReaderregisterBeanDefinitions(Document doc, XmlReaderContext readerContext)方法

此时的this对象变为了DefaultBeanDefinitionDocumentReader

看到下面代码就知道三个操作

  • this.readerContext = readerContext;:将上层函数传进来的XmlReaderContext赋值给自己的属性
  • doc.getDocumentElement()获取Document的节点对象
  • 调用DefaultBeanDefinitionDocumentReaderdoRegisterBeanDefinitions(Element root)方法
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   doRegisterBeanDefinitions(doc.getDocumentElement());
}
4-2-3.3 执行DefaultBeanDefinitionDocumentReaderdoRegisterBeanDefinitions(Element root)方法

该方法注释翻译过来是:在给定的根中注册每个bean定义,我理解就是......好吧我没理解啥。

主要有两个操作

  • this.delegate = createDelegate(getReaderContext(), root, parent);:获取 BeanDefinitionParserDelegate 对象

    简单说一下BeanDefinitionParserDelegate 对象:

    1. 里面维护了Spring的xml配置文的标签常量。(比如 "bean"、"name"、“id”、"singleton"、"scope")
    2. 里面封装了将标签解析为Beandefinition的方法
  • parseBeanDefinitions(root, this.delegate);:一看这方法就知道后面将注册又委托给了this.delegate

/**在给定的根中注册每个bean定义
 * Register each bean definition within the given root {@code <beans/>} element.
 */
@SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
protected void doRegisterBeanDefinitions(Element root) {
   BeanDefinitionParserDelegate parent = this.delegate;
    // 获取 BeanDefinitionParserDelegate 对象
   this.delegate = createDelegate(getReaderContext(), root, parent);
   if (this.delegate.isDefaultNamespace(root)) {
      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
      if (StringUtils.hasText(profileSpec)) {
         String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
               profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
         // We cannot use Profiles.of(...) since profile expressions are not supported
         // in XML config. See SPR-12458 for details.
         if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
            if (logger.isDebugEnabled()) {
               logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                     "] not matching: " + getReaderContext().getResource());
            }
            return;
         }
      }
   }
    // 空方法
   preProcessXml(root);
   // 解析xml 标签
   parseBeanDefinitions(root, this.delegate);
    // 空方法
   postProcessXml(root);
   this.delegate = parent;
}
4-2-3.4 进入到DefaultBeanDefinitionDocumentReaderparseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法

在该方法中,要了解一下Dom解析相关的 Node、Element等对象

因为要解析我们在xml中配置的Bean,所以会parseDefaultElement(ele, delegate)

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               // 只 解析 "import", "alias", "bean", "beans" 标签
               parseDefaultElement(ele, delegate);
            }
            else {
               // 解析 其他的标签 比如 <component-scan> 标签
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}
4-2-3.5 进入到DefaultBeanDefinitionDocumentReaderparseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)方法

因为调试项目中只配置了<bean></bean>标签,所以只关注代码中的processBeanDefinition(ele, delegate);方法

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
       // 解析 bean 标签
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}
4-2-3.6 (this对象变化)进入到DefaultBeanDefinitionDocumentReader的processBeanDefinition(ele, delegate);方法

看代码了解到,将解析任务委托给了BeanDefinitionParserDelegate 对象

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 将 xml 配置信息封装为 Beandefinition
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         //将 Beandefinition 注册到 容器(DefaultListableBeanFactory) 中
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

该方法主要的3个操作

  1. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele):将 xml 配置信息封装为 Beandefinition

    在这段代码中可以得知:

    • xml配置的id属性就是我们Bean的名字
    • 容器中bean的名字是唯一的
    • parseBeanDefinitionElement(ele, beanName, containingBean)方法中还会初始化Beandefinition的一些属性
    • 最后返回BeanDefinitionHolder对象将Beandefinition包装起来
    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));
       }
       // 定义 bean 的名字 为xml中配置的 id 属性
       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);
       }
       // 将xml配置信息 封装成 BeanDefinition 对象
       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.
                   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;
    }
    
  2. 注册Beandefinition到容器中:BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

    • getReaderContext().getRegistry():因为在4-2-3.1中封装的XmlReaderContext对象包含:XmlBeanDefinitionReader对象的所有信息,所以这个方法获取到的对象就是容器对象DefaultListableBeanFactory

    • 该方法将第一个操作获取到的bdHolderBeandefinition对象的持有者)和 容器对象作为参数传入

    • 进入方法后又调用registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())(此时registry就是DefaultListableBeanFactory对象)将Beandefinition对象添加到DefaultListableBeanFactory对象的属性Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256)中,就算注册完成了

    • BeanDefinitionReaderUtilsregisterBeanDefinition()方法代码

      public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {
      
         // Register bean definition under primary name.
         String beanName = definitionHolder.getBeanName();
          // 调用 容器对象(DefaultListableBeanFactory) 注册 Beandefinition
         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
         // Register aliases for bean name, if any.
         String[] aliases = definitionHolder.getAliases();
         if (aliases != null) {
            for (String alias : aliases) {
               registry.registerAlias(beanName, alias);
            }
         }
      }
      
    • registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

      该方法中还有一些逻辑,但是主流程就是将Beandefinition添加到beanDefinitionMap

  3. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))

    该方法注释为Send registration event,我理解是发布一个注册事件。这块没有深入跟踪。

4-2-3.7回到DefaultBeanDefinitionDocumentReaderparseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)方法(4-2-3.5)

此时processBeanDefinition(ele, delegate);方法执行完毕

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}
4-2-3.8回到DefaultBeanDefinitionDocumentReaderparseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法(4-2-3.4)

此时 parseDefaultElement(ele, delegate);方法执行完毕,但是此处是遍历根节点对象,意思就是多个<bean></bean>标签的话就会遍历执行解析重复上面的过程。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               // 只 解析 "import", "alias", "bean", "beans" 标签
               parseDefaultElement(ele, delegate);
            }
            else {
               // 解析 其他的标签 比如 <component-scan> 标签
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}
4-2-3.9回到DefaultBeanDefinitionDocumentReaderdoRegisterBeanDefinitions(Element root)方法(4-2-3.3)
  • 此时执行完了parseBeanDefinitions(root, this.delegate);方法
  • 执行this.delegate = parent,即将this.delegate置为null
protected void doRegisterBeanDefinitions(Element root) {
   // Any nested <beans> elements will cause recursion in this method. In
   // order to propagate and preserve <beans> default-* attributes correctly,
   // keep track of the current (parent) delegate, which may be null. Create
   // the new (child) delegate with a reference to the parent for fallback purposes,
   // then ultimately reset this.delegate back to its original (parent) reference.
   // this behavior emulates a stack of delegates without actually necessitating one.
   BeanDefinitionParserDelegate parent = this.delegate;
   //得到一个 BeanDefinitionParserDelegate 对象
   this.delegate = createDelegate(getReaderContext(), root, parent);

   if (this.delegate.isDefaultNamespace(root)) {
      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
      if (StringUtils.hasText(profileSpec)) {
         String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
               profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
         // We cannot use Profiles.of(...) since profile expressions are not supported
         // in XML config. See SPR-12458 for details.
         if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
            if (logger.isDebugEnabled()) {
               logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                     "] not matching: " + getReaderContext().getResource());
            }
            return;
         }
      }
   }
   // 空方法
   preProcessXml(root);
   // 解析xml 标签
   parseBeanDefinitions(root, this.delegate);
   // 空方法
   postProcessXml(root);

   this.delegate = parent;
}
4-2-3.10回到DefaultBeanDefinitionDocumentReaderregisterBeanDefinitions(Document doc, XmlReaderContext readerContext)方法(4-2-3.2)

此时执行完了doRegisterBeanDefinitions(doc.getDocumentElement());方法

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   doRegisterBeanDefinitions(doc.getDocumentElement());
}
4-2-4回到XmlBeanDefinitionReader对象的registerBeanDefinitions(Document doc, Resource resource)方法(4-2)
  • 此时执行完了documentReader.registerBeanDefinitions(doc, createReaderContext(resource));方法
  • 执行getRegistry().getBeanDefinitionCount() - countBefore计算得出该次注册BeanDefinition的个数
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   int countBefore = getRegistry().getBeanDefinitionCount();
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}
4-2-5 回到XmlBeanDefinitionReaderdoLoadBeanDefinitions(InputSource inputSource, Resource resource)方法(4)
  • 此时执行完了int count = registerBeanDefinitions(doc, resource);方法
  • 然后将 count 返回
/**将 xml文件  装载为  BeanDefinition
 */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {

   try {
      Document doc = doLoadDocument(inputSource, resource);
      int count = registerBeanDefinitions(doc, resource);
      if (logger.isDebugEnabled()) {
         logger.debug("Loaded " + count + " bean definitions from " + resource);
      }
      return count;
   }
   catch (BeanDefinitionStoreException ex) {
      throw ex;
   }
   catch (SAXParseException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
            "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
   }
   catch (SAXException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
            "XML document from " + resource + " is invalid", ex);
   }
   catch (ParserConfigurationException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "Parser configuration exception parsing XML from " + resource, ex);
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "IOException parsing XML document from " + resource, ex);
   }
   catch (Throwable ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
            "Unexpected exception parsing XML document from " + resource, ex);
   }
}

5 回到本文章开始AbstractBeanDefinitionReaderloadBeanDefinitions(String location, @Nullable Set actualResources)方法(1)

  • 此时执行完了count += loadBeanDefinitions(resource);方法
  • 因为我只配置了一个xml,所以只有一个resource
  • 此处的count为容器中总共Beandefinition的数量
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
   Assert.notNull(resources, "Resource array must not be null");
   int count = 0;
   for (Resource resource : resources) {
      // 加载每个资源的 bean 的个数
      count += loadBeanDefinitions(resource);
   }
   return count;
}

总结

  1. loadBeanDefinitions()方法包含了对xml文件的解析以及对Beandefinition对象的封装和注册
  2. loadBeanDefinitions()中最后注册是调用的DefaultListableBeanFactory对象的方法
  3. 解析出的Beandefinition对象都被维护在DefaultListableBeanFactory对象的Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);属性中
  4. 函数调用太深了,但是有规律可循,基本上就是方法重载和任务委托给其他的类来执行任务,要时刻关注this对象是谁
  5. 该文章并没有面面俱到,尤其是最后注册那一块不够详细,但是主流程还是走通了。

欢迎扫码关注

如果喜欢请关注我公众号【程序倾听者】,说出你的故事!我在这里倾听!
文章原文地址