【挑戰 Spring】—– Spring IOC 源碼調試三之loadBeanDefinitions

前言

當你凝視黑夜的時候,黑夜也在凝視着你!日日當精進,幹就完了!上篇Spring IOC 源碼調試二的進度,進行到了重點的AbstractBeanDefinitionReaderloadBeanDefinitions方法**,那這一篇接着進行。原創純手打!實屬不易!求贊!求關注!我不會由於您的不支持而低迷,可是有了您的支持我會變的亢奮!java

項目結構

這是調試代碼node

開始調試

(重點)1.執行AbstractBeanDefinitionReaderloadBeanDefinitions(String location, @Nullable Set actualResources)

該方法中主要操做有:express

  1. ResourceLoader resourceLoader = getResourceLoader():獲取一個ResourceLoader(資源加載器)對象函數

    此時獲取到的ResourceLoader具體實現類是ClassPathXmlApplicationContext對象,詳情請看Spring IOC 源碼調試二2-5部分的第3個操做。post

  2. int count = loadBeanDefinitions(resources):繼續調用XmlBeanDefinitionReaderloadBeanDefinitions(Resource... resources)方法。此時的this對象是XmlBeanDefinitionReaderui

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)方法this

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)方法中spa

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)方法,代碼以下:debug

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. 該文章並無面面俱到,尤爲是最後註冊那一塊不夠詳細,可是主流程仍是走通了。

歡迎掃碼關注

若是喜歡請關注我公衆號【程序傾聽者】,說出你的故事!我在這裏傾聽!
文章原文地址

相關文章
相關標籤/搜索