在XmlBeanFactory类中,XmlBeanFactory通过构造方法,以接近于下面这样的方式进行xml解析
new XmlBeanDefinitionReader(this).loadBeanDefinitions(resource);
所以我们就来讲一讲XmlBeanDefinitionReader类,照例,先看看官方是怎么说这个对象的
*用于XML Bean定义的Bean定义读取器。
*将实际的XML文档读取委托给实现
*{@link BeanDefinitionDocumentReader}接口的。
*
*<p>通常应用于
*{@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
*或者{@link org.springframework.context.support.GenericApplicationContext}。
*
*<p>此类加载一个DOM文档并将BeanDefinitionDocumentReader应用于该文档。
*文档读取器将向给定的bean工厂注册每个bean定义,
*谈后者对
*{@link org.springframework.beans.factory.support.BeanDefinitionRegistry}接口。
*
*@作者Juergen Hoeller
*@作者Rob Harrop
*@作者Chris Beams
*@自2003年11月26日起
*@请参阅setDocumentReaderClass
*@请参阅BeanDefinitionDocumentReader
*@请参阅DefaultBeanDefinitionDocumentReader
*@请参阅BeanDefinitionRegistry
*@请参见org.springframework.beans.factory.support.DefaultListableBeanFactory
*@请参见org.springframework.context.support.genericaplicationcontext
很明显,这就是我们想要寻找的xml解析类
查看构造方法
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
super方法
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
保证xml解析入口类不为空
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
将入口类赋为成员变量
this.registry = registry;
// Determine ResourceLoader to use.
判断xml入口类是否带有类加载器
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
否则使用默认类加载器
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
如果可能,继承环境,本质上就是将可以复用的Java对象尝试进行复用,节省资源开销
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
接下来就是该类的关键方法,loadBeanDefinitions方法,该方法是解析的执行方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
保证资源对象不为空
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
取出加载的资源对象,防止循环加载
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
若已存在该资源对象,抛出异常
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
获取资源对象的io连接
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
将io连接交给包装类处理
InputSource inputSource = new InputSource(inputStream);
若资源带有编码方式,也一并交给包装类
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
开始解析
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
解析失败抛出异常
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
将该资源对象剔除出已加载的资源对象
currentResources.remove(encodedResource);
若此时没有任何加载的资源对象,将存放资源对象的集合重置
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
进入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);
}
}
进入doLoadDocument方法
五个参数分别为,io包装对象,解析器对象,记录器对象(记录错误的xml解析,方便查找错误),解析模式(
XSD或DTD),解析器是否应该解析xml命名空间
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
loadDocument方法通过上面的五个参数获取解析io的解析对象
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);
}