/** * 用户加载xml文档的策略接口 * Strategy interface for loading an XML {@link Document}. * * @author Rob Harrop * @since 2.0 * @see DefaultDocumentLoader */ publicinterfaceDocumentLoader{ /** * 从inputstream 中加载 document * Load a {@link Document document} from the supplied {@link InputSource source}. * @param inputSource the source of the document that is to be loaded 加载document的源 * @param entityResolver the resolver that is to be used to resolve any entities 实体的解析器 * @param errorHandler used to report any errors during document loading 文档加载错误的处理器 * @param validationMode the type of validation 数据验证模型 * {@link org.springframework.util.xml.XmlValidationModeDetector#VALIDATION_DTD DTD} * or {@link org.springframework.util.xml.XmlValidationModeDetector#VALIDATION_XSD XSD}) * @param namespaceAware {@code true} if support for XML namespaces is to be provided 是都需要支持 名称空间 * @return the loaded {@link Document document} * @throws Exception if an error occurs */ Document loadDocument( InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception; }
/** * 创建documentBuider工厂,通过检验模型和是否支持xml名称空间 * Create the {@link DocumentBuilderFactory} instance. * @param validationMode the type of validation: {@link XmlValidationModeDetector#VALIDATION_DTD DTD} * or {@link XmlValidationModeDetector#VALIDATION_XSD XSD}) * @param namespaceAware whether the returned factory is to provide support for XML namespaces * @return the JAXP DocumentBuilderFactory * @throws ParserConfigurationException if we failed to build a proper DocumentBuilderFactory */ protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException { // 默认创建 com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl 类 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(namespaceAware); //1.判断是否有验证 if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) { factory.setValidating(true); if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) { // Enforce namespace aware for XSD... //如果是xsd验证 则体重xml名称空间支持 factory.setNamespaceAware(true); try { factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE); } catch (IllegalArgumentException ex) { ParserConfigurationException pcex = new ParserConfigurationException( "Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " + "Upgrade to Apache Xerces (or Java 1.5) for full XSD support."); pcex.initCause(ex); throw pcex; } } } return factory; }
/** Suffix for DTD files. */ publicstaticfinal String DTD_SUFFIX = ".dtd"; /** Suffix for schema definition files. */ publicstaticfinal String XSD_SUFFIX = ".xsd"; /** * 创建默认的解析器 * Create a new DelegatingEntityResolver that delegates to * a default {@link BeansDtdResolver} and a default {@link PluggableSchemaResolver}. * <p>Configures the {@link PluggableSchemaResolver} with the supplied * {@link ClassLoader}. * @param classLoader the ClassLoader to use for loading * (can be {@code null}) to use the default ClassLoader) */ publicDelegatingEntityResolver(@Nullable ClassLoader classLoader){ //dtd解析器 this.dtdResolver = new BeansDtdResolver(); //xsd解析器 this.schemaResolver = new PluggableSchemaResolver(classLoader); } /** * 指定 dtd 和 xsd 的解析器来创建 * Create a new DelegatingEntityResolver that delegates to * the given {@link EntityResolver EntityResolvers}. * @param dtdResolver the EntityResolver to resolve DTDs with * @param schemaResolver the EntityResolver to resolve XML schemas with */ publicDelegatingEntityResolver(EntityResolver dtdResolver, EntityResolver schemaResolver){ Assert.notNull(dtdResolver, "'dtdResolver' is required"); Assert.notNull(schemaResolver, "'schemaResolver' is required"); this.dtdResolver = dtdResolver; this.schemaResolver = schemaResolver; }
@Override @Nullable public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId)throws IOException { if (logger.isTraceEnabled()) { logger.trace("Trying to resolve XML entity with public ID [" + publicId + "] and system ID [" + systemId + "]"); } //1. 校验是否是 dtd 后缀 if (systemId != null && systemId.endsWith(DTD_EXTENSION)) { int lastPathSeparator = systemId.lastIndexOf('/'); int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator); //2. 校验路径的 名字是都是 spring-beans if (dtdNameStart != -1) { String dtdFile = DTD_NAME + DTD_EXTENSION; if (logger.isTraceEnabled()) { logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath"); } try { //3. spring-beans.dtd 加载 Resource resource = new ClassPathResource(dtdFile, getClass()); InputSource source = new InputSource(resource.getInputStream()); source.setPublicId(publicId); source.setSystemId(systemId); if (logger.isTraceEnabled()) { logger.trace("Found beans DTD [" + systemId + "] in classpath: " + dtdFile); } return source; } catch (FileNotFoundException ex) { if (logger.isDebugEnabled()) { logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex); } } } } // 使用默认行为,从网络上下载 // Fall back to the parser's default behavior. returnnull; }