歡迎光臨
每天分享高質量文章

【死磕 Spring】—– IOC 之 獲取驗證模型

點選上方“Java技術驛站”,選擇“置頂公眾號”。

有內涵、有價值的文章第一時間送達!

精品專欄

 

在上篇部落格【死磕Spring】—– IOC 之 載入 Bean 中提到,在核心邏輯方法 doLoadBeanDefinitions()中主要是做三件事情。

  1. 呼叫 getValidationModeForResource() 獲取 xml 檔案的驗證樣式

  2. 呼叫 loadDocument() 根據 xml 檔案獲取相應的 Document 實體。

  3. 呼叫 registerBeanDefinitions() 註冊 Bean 實體。

這篇部落格主要分析獲取 xml 檔案的驗證樣式。

XML 檔案的驗證樣式保證了 XML 檔案的正確性

DTD 與 XSD 的區別

DTD(Document Type Definition),即檔案型別定義,為 XML 檔案的驗證機制,屬於 XML 檔案中組成的一部分。DTD 是一種保證 XML 檔案格式正確的有效驗證方式,它定義了相關 XML 檔案的元素、屬性、排列方式、元素的內容型別以及元素的層次結構。其實 DTD 就相當於 XML 中的 “詞彙”和“語法”,我們可以透過比較 XML 檔案和 DTD 檔案 來看檔案是否符合規範,元素和標簽使用是否正確。

要在 Spring 中使用 DTD,需要在 Spring XML 檔案頭部宣告:

  1. xml version="1.0" encoding="UTF-8"?>

  2. "-//SPRING//DTD BEAN//EN"  "http://www.springframework.org/dtd/spring-beans.dtd">

DTD 在一定的階段推動了 XML 的發展,但是它本身存在著一些缺陷:

  1. 它沒有使用 XML 格式,而是自己定義了一套格式,相對解析器的重用性較差;而且 DTD 的構建和訪問沒有標準的程式設計介面,因而解析器很難簡單的解析 DTD 檔案。

  2. DTD 對元素的型別限制較少;同時其他的約束力也叫弱。

  3. DTD 擴充套件能力較差。

  4. 基於正則運算式的 DTD 檔案的描述能力有限。

針對 DTD 的缺陷,W3C 在 2001 年推出 XSD。XSD(XML Schemas Definition)即 XML Schema 語言。XML Schema 本身就是一個 XML檔案,使用的是 XML 語法,因此可以很方便的解析 XSD 檔案。相對於 DTD,XSD 具有如下優勢:

  • XML Schema基於XML,沒有專門的語法

  • XML Schema可以象其他XML檔案一樣解析和處理

  • XML Schema比DTD提供了更豐富的資料型別.

  • XML Schema提供可擴充的資料模型。

  • XML Schema支援綜合名稱空間

  • XML Schema支援屬性組。

getValidationModeForResource() 分析

  1.    protected int getValidationModeForResource(Resource resource) {

  2.        // 獲取指定的驗證樣式

  3.        int validationModeToUse = getValidationMode();

  4.        // 如果手動指定,則直接傳回

  5.        if (validationModeToUse != VALIDATION_AUTO) {

  6.            return validationModeToUse;

  7.        }

  8.        // 透過程式檢測

  9.        int detectedMode = detectValidationMode(resource);

  10.        if (detectedMode != VALIDATION_AUTO) {

  11.            return detectedMode;

  12.        }

  13.        // 出現異常,傳回 XSD

  14.        return VALIDATION_XSD;

  15.    }

如果指定了 XML 檔案的的驗證樣式(呼叫 XmlBeanDefinitionReader.setValidating(booleanvalidating))則直接傳回指定的驗證樣式,否則呼叫 detectValidationMode() 獲取相應的驗證樣式,如下:

  1.    protected int detectValidationMode(Resource resource) {

  2.        if (resource.isOpen()) {

  3.            throw new BeanDefinitionStoreException(

  4.                    "Passed-in Resource [" + resource + "] contains an open stream: " +

  5.                    "cannot determine validation mode automatically. Either pass in a Resource " +

  6.                    "that is able to create fresh streams, or explicitly specify the validationMode " +

  7.                    "on your XmlBeanDefinitionReader instance.");

  8.        }

  9.        InputStream inputStream;

  10.        try {

  11.            inputStream = resource.getInputStream();

  12.        }

  13.        catch (IOException ex) {

  14.            throw new BeanDefinitionStoreException(

  15.                    "Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +

  16.                    "Did you attempt to load directly from a SAX InputSource without specifying the " +

  17.                    "validationMode on your XmlBeanDefinitionReader instance?", ex);

  18.        }

  19.        try {

  20.          // 核心方法

  21.            return this.validationModeDetector.detectValidationMode(inputStream);

  22.        }

  23.        catch (IOException ex) {

  24.            throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +

  25.                    resource + "]: an error occurred whilst reading from the InputStream.", ex);

  26.        }

  27.    }

前面一大堆的程式碼,核心在於 this.validationModeDetector.detectValidationMode(inputStream),validationModeDetector 定義為 XmlValidationModeDetector,所以驗證樣式的獲取委託給 XmlValidationModeDetectordetectValidationMode() 方法。

  1.    public int detectValidationMode(InputStream inputStream) throws IOException {

  2.        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

  3.        try {

  4.            boolean isDtdValidated = false;

  5.            String content;

  6.            // 一行一行讀取 xml 檔案的內容

  7.            while ((content = reader.readLine()) != null) {

  8.                content = consumeCommentTokens(content);

  9.                if (this.inComment || !StringUtils.hasText(content)) {

  10.                    continue;

  11.                }

  12.                // 包含 DOCTYPE 為 DTD 樣式

  13.                if (hasDoctype(content)) {

  14.                    isDtdValidated = true;

  15.                    break;

  16.                }

  17.                // 讀取 < 開始符號,驗證樣式一定會在 < 符號之前

  18.                if (hasOpeningTag(content)) {

  19.                    // End of meaningful data...

  20.                    break;

  21.                }

  22.            }

  23.        // 為 true 傳回 DTD,否則傳回 XSD

  24.            return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);

  25.        }

  26.        catch (CharConversionException ex) {

  27.            // 出現異常,為 XSD

  28.            return VALIDATION_AUTO;

  29.        }

  30.        finally {

  31.            reader.close();

  32.        }

  33.    }

從程式碼中看,主要是透過讀取 XML 檔案的內容,判斷內容中是否包含有 DOCTYPE ,如果是 則為 DTD,否則為 XSD,當然只會讀取到 第一個 "

好了,XML 檔案的驗證樣式分析完畢,下篇分析 doLoadBeanDefinitions() 的第二個步驟:獲取 Document 實體。

【死磕 Spring】----- IOC 之 載入 Bean

【死磕 Spring】----- IOC 之 Spring 統一資源載入策略

【死磕 Spring】----- IOC 之深入理解 Spring IoC

END

贊(0)

分享創造快樂

© 2024 知識星球   網站地圖