1.上一篇文档大概回顾了Resource resource = new ClassPathResource("beanFactoryTest.xml")的加载机制;
本次回顾从 BeanFactory factory = new XmlBeanFactory(resource);这句话开始;public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
其中reader就是 XmlBeanDefinitionReader类的对象;
首先从构造方法看起:EncodeResource实际就是对流做了一层封装;
我们再次整理一下数据准备阶段的逻辑,首先对传入的resource参数进行封装,目的是考虑可能存在的编码要求的情况,其次是通过SAX读取XML文件的方式来准备InputSource对象,最后把准备的数据传入核心处理部分doLoadBeanDefinitions(inputSource, encodedResource.getResource());
下面进入doLoadBeanDefinitions()方法:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
这个方法除去异常,其实只做了三件事:
(1):获取对XML文件的验证模式 ;(2):加载XML文件,并得到对应的Document;(3)根据Document注册Bean信息;
下面进入doLoadDocument方法:
这个doLoadDocument方法关注两个点:getValidationModeForResource()方法:此方法就是获取资源的验证模式DTD和XSD两个模式,还有一个时genEntityResolver()方法
下面进入这个方法:getValidationModeForResource()
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; }下面进入
genEntityResolver():
那么EntityResolver到底是做什么用的呢;验证文件默认加载方式是通过URL进行网络下载获取的,这样会造成延迟,用户体验也不好,一般的做法都是将验证文件放置在自己的工程里,那么怎么才能将这个URL转化为自己的工程里面呢?以加载DTD文件为例来看看spring中是如何实现的,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; }
下面就进入构造document了:步骤为@Override @Nullable public InputSource resolveEntity(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 + "]"); } if (systemId != null && systemId.endsWith(DTD_EXTENSION)) { int lastPathSeparator = systemId.lastIndexOf("/"); int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator); if (dtdNameStart != -1) { //spring-beans + .dtd String dtdFile = DTD_NAME + DTD_EXTENSION; if (logger.isTraceEnabled()) { logger.trace("Trying to locate [" + dtdFile + "] in Spring jar onclasspath"); } try { //此构造方法传入getClass() 文件名需要和此类在同一个包中; // Resource resource = new ClassPathResource("文件名") 以classpath为基础的 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 classpath", ex); } } } } // Use the default behavior -> download from website or wherever. return null; }
1.DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
2.DocumentBuilder builder = factory.newDocumentBuilder();
3.builder.parse(inputSource);
下面为详细代码--- 获取factory:
第二步为:获取DocumentBuilder
第三步为:用builder构造document
至此已经获取document文档。