经过验证模式准备的步骤就可以进行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() + "]");
}
//准备对xml进行解析
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(namespaceAware);
if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
factory.setValidating(true);
if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
// Enforce namespace aware for XSD...
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;
}
其中的参数entityResolver是通过调用XmlBeanDefinitionReader中方法getEntityResolver()传入的
protected EntityResolver getEntityResolver() {
//一开始的时候entityResolver 为空
if (this.entityResolver == null) {
// Determine default EntityResolver to use.
//再XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader中定义了resourceLoader为ResourceLoader
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader != null) {
this.entityResolver = new ResourceEntityResolver(resourceLoader);
}
else {
this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
}
}
return this.entityResolver;
}
//其中的getResourceLoader方法
public ResourceLoader getResourceLoader() {
//找个resourceLoader再AbstractBeanDefinitionReader中定义
return this.resourceLoader;
}
//查看AbstractBeanDefinitionReader类的初始化方法,
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
//在XmlBeanFactory会初始化XmlBeanDefinitionReader,而XmlBeanDefinitionReader继承了AbstractBeanDefinitionReader,所以在初始化XmlBeanFactory的时候就已经吧registry传入了,这里的register为XmlBeanFactory所以后面选择的resourceLoader为PathMatchingResourcePatternResolver对象
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
...
}
//PathMatchingResourcePatternResolver的初始化方法
public PathMatchingResourcePatternResolver() {
//这里的resourceLoader为默认的
this.resourceLoader = new DefaultResourceLoader();
}
1.EntityResolver用法(接口)
官网的解释是:如果SAX应用程序需要实现自定义处理外部实体,则必须实现此接口并使用setEntityResolver()方法向SAX驱动器注册一个实例。也就是说,对于解析一个XML,SAX首先读取该XML文档的声明,根据声明去寻找相应的DTD定义,以便对文档进行一个验证。
默认的寻找规则,即通过网络(现实上就是声明的DTD的URI地址)来下载相应的DTD声明,并进行认证。
EntityResolver的作用是项目本身就可以提供一个如何寻找DTD声明的方法,即有程序来实现寻找DTD声明的过程,比如我们将DTD温江放到项目中某处,在是现实直接将此文档读取并返回给SAX即可。
Spring中通过setEntityResolver()方法对EntityResolver的获取,,Spring中使用DelegatingEntityResolver类为EntityResolver的实现类,resolveEntity实现方法如下
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
if (systemId != null) {
if (systemId.endsWith(DTD_SUFFIX)) {
//todo 如果DTD文件那么是从这里解析
return this.dtdResolver.resolveEntity(publicId, systemId);
}
else if (systemId.endsWith(XSD_SUFFIX)) {
//todo 通过调用META—INF/Spring.schemas解析
return this.schemaResolver.resolveEntity(publicId, systemId);
}
}
return null;
}