原文出自:http://cmsblogs.comjava
在上篇博客【死磕Spring】----- IOC 之 加載 Bean 中提到,在覈心邏輯方法 doLoadBeanDefinitions()
中主要是作三件事情。正則表達式
getValidationModeForResource()
獲取 xml 文件的驗證模式loadDocument()
根據 xml 文件獲取相應的 Document 實例。registerBeanDefinitions()
註冊 Bean 實例。這篇博客主要分析獲取 xml 文件的驗證模式。spring
XML 文件的驗證模式保證了 XML 文件的正確性編程
DTD(Document Type Definition),即文檔類型定義,爲 XML 文件的驗證機制,屬於 XML 文件中組成的一部分。DTD 是一種保證 XML 文檔格式正確的有效驗證方式,它定義了相關 XML 文檔的元素、屬性、排列方式、元素的內容類型以及元素的層次結構。其實 DTD 就至關於 XML 中的 「詞彙」和「語法」,咱們能夠經過比較 XML 文件和 DTD 文件 來看文檔是否符合規範,元素和標籤使用是否正確。this
要在 Spring 中使用 DTD,須要在 Spring XML 文件頭部聲明:spa
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
DTD 在必定的階段推進了 XML 的發展,可是它自己存在着一些缺陷:code
針對 DTD 的缺陷,W3C 在 2001 年推出 XSD。XSD(XML Schemas Definition)即 XML Schema 語言。XML Schema 自己就是一個 XML文檔,使用的是 XML 語法,所以能夠很方便的解析 XSD 文檔。相對於 DTD,XSD 具備以下優點:xml
protected int getValidationModeForResource(Resource resource) { // 獲取指定的驗證模式 int validationModeToUse = getValidationMode(); // 若是手動指定,則直接返回 if (validationModeToUse != VALIDATION_AUTO) { return validationModeToUse; } // 經過程序檢測 int detectedMode = detectValidationMode(resource); if (detectedMode != VALIDATION_AUTO) { return detectedMode; } // 出現異常,返回 XSD return VALIDATION_XSD; }
若是指定了 XML 文件的的驗證模式(調用XmlBeanDefinitionReader.setValidating(boolean validating)
)則直接返回指定的驗證模式,不然調用 detectValidationMode()
獲取相應的驗證模式,以下:blog
protected int detectValidationMode(Resource resource) { if (resource.isOpen()) { throw new BeanDefinitionStoreException( "Passed-in Resource [" + resource + "] contains an open stream: " + "cannot determine validation mode automatically. Either pass in a Resource " + "that is able to create fresh streams, or explicitly specify the validationMode " + "on your XmlBeanDefinitionReader instance."); } InputStream inputStream; try { inputStream = resource.getInputStream(); } catch (IOException ex) { throw new BeanDefinitionStoreException( "Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " + "Did you attempt to load directly from a SAX InputSource without specifying the " + "validationMode on your XmlBeanDefinitionReader instance?", ex); } try { // 核心方法 return this.validationModeDetector.detectValidationMode(inputStream); } catch (IOException ex) { throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: an error occurred whilst reading from the InputStream.", ex); } }
前面一大堆的代碼,核心在於 this.validationModeDetector.detectValidationMode(inputStream)
,validationModeDetector 定義爲 XmlValidationModeDetector
,因此驗證模式的獲取委託給 XmlValidationModeDetector
的 detectValidationMode()
方法。接口
public int detectValidationMode(InputStream inputStream) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); try { boolean isDtdValidated = false; String content; // 一行一行讀取 xml 文件的內容 while ((content = reader.readLine()) != null) { content = consumeCommentTokens(content); if (this.inComment || !StringUtils.hasText(content)) { continue; } // 包含 DOCTYPE 爲 DTD 模式 if (hasDoctype(content)) { isDtdValidated = true; break; } // 讀取 < 開始符號,驗證模式必定會在 < 符號以前 if (hasOpeningTag(content)) { // End of meaningful data... break; } } // 爲 true 返回 DTD,不然返回 XSD return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD); } catch (CharConversionException ex) { // 出現異常,爲 XSD return VALIDATION_AUTO; } finally { reader.close(); } }
從代碼中看,主要是經過讀取 XML 文件的內容,判斷內容中是否包含有 DOCTYPE ,若是是 則爲 DTD,不然爲 XSD,固然只會讀取到 第一個 "<" 處,由於 驗證模式必定會在第一個 「<」 以前。若是當中出現了 CharConversionException 異常,則爲 XSD模式。
好了,XML 文件的驗證模式分析完畢,下篇分析 doLoadBeanDefinitions()
的第二個步驟:獲取 Document 實例。