spring源码深度解析笔记(五)

通过了验证模式准备的不走就可以进行Document加载了。同样XmlBeanFactoryReader类对于文档读取并没有亲力亲为,而是委托了DocumentLoader去执行。这里的DocumentLoader是个借口。而真正调用的是DefaultDocumentLoader。

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

        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        return builder.parse(inputSource);
    }

这段代码通过SAX解析XML文档。首先创建DocumentBuiderFactory,在通过DocumentBuilderFactory创建DocumentBuilder。进行解析inputSource来返回Document对象。
在loadDocument方法中涉及一个参数EntityResolver,那什么是EntityResovler呢?
EntityResolver的作用是项目本身就可以提供一个如何寻找DTD声明的方法,既有程序来实现寻找DTD声明的过程。比如我们将DTD文件放在项目中的某处。在实现时直接将此文档读取返回给sax即可。这样就避免了通过网络来寻找相应的声明。
首先看entityResolver的接口方法声明:

protected EntityResolver getEntityResolver() {
        if (this.entityResolver == null) {
            // Determine default EntityResolver to use.
            ResourceLoader resourceLoader = getResourceLoader();
            if (resourceLoader != null) {
                this.entityResolver = new ResourceEntityResolver(resourceLoader);
            }
            else {
                this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
            }
        }
        return this.entityResolver;
    }

    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if (systemId != null) {
            if (systemId.endsWith(DTD_SUFFIX)) {
                return this.dtdResolver.resolveEntity(publicId, systemId);
            }
            else if (systemId.endsWith(XSD_SUFFIX)) {
                return this.schemaResolver.resolveEntity(publicId, systemId);
            }
        }
        return null;
    }

对于不同的验证模式,Spring使用了不同的解析器解析。

public InputSource resolveEntity(String publicId, String systemId) throws IOException {
        if (logger.isTraceEnabled()) {
            logger.trace("Trying to resolve XML entity with public ID [" + publicId +
                    "] and system ID [" + systemId + "]");
        }
        if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
            int lastPathSeparator = systemId.lastIndexOf("/");
            for (String DTD_NAME : DTD_NAMES) {
                int dtdNameStart = systemId.indexOf(DTD_NAME);
                if (dtdNameStart > lastPathSeparator) {
                    String dtdFile = systemId.substring(dtdNameStart);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Trying to locate [" + dtdFile + "] in Spring jar");
                    }
                    try {
                        Resource resource = new ClassPathResource(dtdFile, getClass());
                        InputSource source = new InputSource(resource.getInputStream());
                        source.setPublicId(publicId);
                        source.setSystemId(systemId);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
                        }
                        return source;
                    }
                    catch (IOException ex) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in class path", ex);
                        }
                    }

                }
            }
        }

        // Use the default behavior -> download from website or wherever.
        return null;
    }

加载DTD类型的beansDtdResolver的resolveEntity是直接截取systemId最后的xx.dtd然后去当前路径下寻找,而加载xsd类型的pluggableschemaResolver类resolveEntity是默认到META-INF/Spring.schemas文件中找到systemid所对应的xsd文件加载。

你可能感兴趣的:(spring源码解析,spring,dtd,spring源码解析)