Spring如何解析XML文件——Spring源碼之XML初解析


首先,在我的這篇博客中已經說到容器是怎么初步實現的,並且要使用XmlBeanDefinitionReader對象對Xml文件進行解析,那么Xml文件是如何進行解析的,將在這片博客中進行一些陳述.


數據准備階段

准備的目的是封裝resource參數,目的是為了考慮到Resource可能存在編碼要求的情況,其次,通過SAX讀取XML文件的方式來准備InputSource對象,最后將參數傳遞到最核心的實現部分doLoadBeanDefinitions(inputSource,encodedResource.getResource())

封裝Resource

調用XmlBeanDefinitionReaderloadBeanDefinitions(Resource resource)方法時,首先將resource對象進行再次封裝成EncodedResource,查看源碼可以發現里面增加了字符集和編碼的封裝,從命名上來看也可以體現出來,將資源封裝完成后,就調用重載的同名函數loadBeanDefinitions(EncodedResource resource)進行正式的解析.

數據准備操作

在重載方法里面首先通過Set<EncodedResource> currentResources屬性來記錄已經加載的資源,其次,從EncodedResource對象中獲取封裝好的Resource對象,並獲取其inputStream,將獲取到的輸入流與SAX解析的InputSource綁定,接下來就進入到了核心的實現部分:doLoadBeanDefinitions(inputSource,encodedResource.getResource())

核心實現

核心部分有兩個關鍵步驟:

  1. 調用doLoadDocument(inputSource.resource)方法獲取Document
  2. 根據返回的Document信息注冊Bean信息

這兩個步驟支持着整個Spring容器部分的實現基礎

獲取Document

進入方法體后,將Document的創建交給DefaultDocumentLoader documentLoader屬性的loadDocument()方法,該方法聲明如下:

Document loadDocument(
			InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
			throws Exception;

調用情況:

documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware())
  • InputSource:SAX解析需要使用到的對象

  • EntityResolver:它的作用是項目本身就可以提供一個如何尋找DTD聲明的方法,由程序來實現尋找DTD聲明的過程,將DTD文件放到項目中某處,在實現時直接將此文檔讀取並返回給SAX即可,避免了必須通過網絡來尋找相應的聲明.

在這個接口中定義了一個方法

InputSource resolveEntity (String publicId,String systemId)
        throws SAXException, IOException;

如果解析的驗證模式是XSD:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd>

那么.此時得到的兩個參數值分別是:

publicId:null
systemId:http://www.springframework.org/schema/beans/spring-beans.xsd

如果解析的驗證模式是DTD:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//Spring//DTD BEAN 2.0//EN" "http://www.Springframework.org/dtd/Spring-beans-2.0.dtd"

那么,此時得到的兩個參數值分別是:

publicId😕/Spring//DTD BEAN 2.0//EN
systemId:http://www.Springframework.org/dtd/Spring-beans-2.0.dtd

而對於不同的驗證模式,Spring使用了不同的解析器,當使用DTD驗證時,Spring會截取后面的*.dtd,並直接到當前目錄去尋找,當使用XSD驗證時,Spring會到META-INF/Spring.schemas文件中去匹配相應的systemId並加載對應的XSD文件

  • validationMode:驗證模式

首先,為了保證XML文件的正確性,有常見兩種驗證模式:DTDXSD

兩種驗證模式的區別

我對這兩種的區別目前還不是很詳細,只能簡略的給出定義,但我看到的最直觀的區別是,DTD驗證需要單獨寫出一個標簽<!DOCTYPE ...>,而XSD驗證會將信息寫入<beans xmlns="...">結點

DTD

DTD(Document Type Definition)即文檔類型定義,是一種保證XML文檔格式正確的有效方法,可以通過比較XML文檔和DTD文件來看文檔是否符合規范.

XSD

XML Schema語言就是XSD(XML Schema Definition),描述了XML文檔的結構,可以用一個指定的XML Schema來驗證XML文檔,以檢查文檔是否符合要求.

驗證模式的讀取

驗證模式的讀取非常簡單,在getValidationModeForResource(resource)方法中先獲取當前設定的驗證模式是不是自動選擇,源碼中是這么解釋的since we cannot find a clear indication,當找不到一個確切的驗證模式時,采用這種方式,然后判斷當前resource對象中采用的是什么驗證模式,通過檢索字符串的方式,當存在DOCTYPE的時候,就采用DTD驗證模式,否則采用XSD驗證模式

  • namespaceAware:一個布爾值,默認為false,在前面可以看到,在使用XSD驗證的時候會有xmlns="",其實就是XML namespace的縮寫,可以有多個命名空間,如果使用的是XSD解析,將會把這個值改為true

解析並注冊BeanDefinitions

在上一步得到Docment對象之后,調用registerBeanDefinitions(Document doc,Resource resource)

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;
	}

而在調用documentReader對象方法中,才開始進行正式的解析工作

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();
		doRegisterBeanDefinitions(root);
	}

解析的工作全權交給doRegisterBeanDefinition(root)方法實現,這樣XML文件就正式進入了解析步驟,至於怎么解析的,博主將慢慢學習並寫入后續博客.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM