1. 程式人生 > >spring原始碼深度解析筆記(四)

spring原始碼深度解析筆記(四)

DTD與XSD的區別 DTD(Document Type Definition)即文件型別定義,是一種XML約束模式語言,是XML檔案的驗證機制,是屬於XML檔案組成的一部分。DTD是一種保證XML文件格式正確的有效方法,可以通過比較XML文件和DTD檔案來看文件是否符合規範,元素和標籤使用是否正確。一個DTD文件包含:元素的定義規則,元素間關係的定義規則,元素可使用的屬性,可使用的屬性或者實體規則。 要使用DTD驗證模式的時候需要在XML檔案的頭部宣告,以下是Spring中使用DTD宣告方式的程式碼:

XML Schema語言就是XSD(XML Schema Definition)。XML Schema描述了XML文件的結構。可以用一個指定的XML Schema來驗證某個XML文件,以檢查該XML文件是否符合其要求。文件設計者可以通過XML Schema指定一個XML文件所允許的結構和內容,並可據此檢查一個XML文件是否有效。XML Schema本身就是一個XML文件,它符合XML語法結構。可以通過通用的XML解析器解析它。 在使用XML Schema文件對XML例項文件進行檢驗,除了要宣告名稱空間以外(xmlns=

http://www.Springframework.org/schema/beans),還必須指定該名稱空間所對應的XML Schema文件的儲存位置。通過schemaLocation屬性來指定名稱空間所對應的XML Schema的儲存位置,它包含兩個部分:名稱空間的URI和該名稱空間所標識的XML Schema檔案的儲存位置或URL地址。 瞭解了DTD與XSD的區別後分析Spring中對於驗證模式的提取就更容易的多了。通過之前的分析我鎖定了spring通過getValidationModelForResource方法來獲取對應資源的驗證模式。

protected int getValidationModeForResource
(Resource resource) { int validationModeToUse = getValidationMode(); //如果手動指定了驗證模式則使用指定的驗證模式 if (validationModeToUse != VALIDATION_AUTO) { return validationModeToUse; } //如果未指定則使用自動驗證 int detectedMode = detectValidationMode(resource); if
(detectedMode != VALIDATION_AUTO) { return detectedMode; } // Hmm, we didn't get a clear indication... Let's assume XSD, // since apparently no DTD declaration has been found up until // detection stopped (before finding the document's root tag). return VALIDATION_XSD; }

方法的實現挺簡單的。無非是如果設定了驗證模式則使用驗證模式(可以通過對呼叫XmlBeanDefinitionReader中的setValidationModel方法進行設定),否則使用自動檢測的方式。而自動檢測模式的功能是在函式detectValidationMode方法中實現的。在detectValidationMode函式中又將自動檢測驗證模式的工作委託給了專門處理類XmlValidationModelDetector,呼叫了XmlValidataionModelDetector的validationModeDetector方法。

    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);
        }
    }
    public int detectValidationMode(InputStream inputStream) throws IOException {
        // Peek into the file to look for DOCTYPE.
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        try {
            boolean isDtdValidated = false;
            String content;
            while ((content = reader.readLine()) != null) {
                content = consumeCommentTokens(content);
                if (this.inComment || !StringUtils.hasText(content)) {
                    continue;
                }
                if (hasDoctype(content)) {
                    isDtdValidated = true;
                    break;
                }
                if (hasOpeningTag(content)) {
                    // End of meaningful data...
                    break;
                }
            }
            return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
        }
        catch (CharConversionException ex) {
            // Choked on some character encoding...
            // Leave the decision up to the caller.
            return VALIDATION_AUTO;
        }
        finally {
            reader.close();
        }
    }