XmlBeanDefinitionReader是BeanDefinitionReader三大读取器的其中一个,XmlBeanDefinitionReader继承于AbstractBeanDefinitionReader。XmlBeanDefinitionReader是为了读取Xml文件中的Bean而设计出来的。
AbstractBeanDefinitionReader内部有registry成员属性,理所当然可以往IOC容器里面添加BeanDefinition。XmlBeanDefinitionReader继承于AbstractBeanDefinitionReader,必定也能将BeanDefinition注册到容器里面。
请记住这个AbstractBeanDefinitionReader中的成员属性,因为后面XmlBeanDefinitionReader会通过调用AbstractBeanDefinitionReader的getRegistry()拿到这个成员属性
//AbstractBeanDefinitionReader的私有成员属性
private final BeanDefinitionRegistry registry;
//AbstractBeanDefinitionReader中的公共方法
@Override
public final BeanDefinitionRegistry getRegistry() {
return this.registry;
}
其实两者都是用来定义和约束XML的结构信息的,如:有哪些节点,节点之间的结构关系等等。
我们平时的bean定义的xml文件里面的xmlns:xsi , xsi:schemaLocation就是XSD,用来约束xml文件结构。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
从注释就可以知道,这是xml验证模式的标志符,看看上面写的DTD和XSD大概就知道这几个变量的作用了。
/**
* Indicates that the validation should be disabled.
*/
//无检验
public static final int VALIDATION_NONE = XmlValidationModeDetector.VALIDATION_NONE;
/**
* Indicates that the validation mode should be detected automatically.
*/
//自动检测XML的检验模式
public static final int VALIDATION_AUTO = XmlValidationModeDetector.VALIDATION_AUTO;
/**
* Indicates that DTD validation should be used.
*/
//用DTD去进行校验
public static final int VALIDATION_DTD = XmlValidationModeDetector.VALIDATION_DTD;
/**
* Indicates that XSD validation should be used.
*/
//用XSD去进行校验
public static final int VALIDATION_XSD = XmlValidationModeDetector.VALIDATION_XSD;
//默认自动检测
private int validationMode = VALIDATION_AUTO;
//XML校验模式侦查器
private final XmlValidationModeDetector validationModeDetector = new XmlValidationModeDetector();
实现BeanDefinitionReader接口的重要方法
//这里是实现BeanDefinitionReader接口的重要方法
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
//loadBeanDefinitions具体的实现方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
//已经加载的Resource
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
//判断是否重复加载
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
//封装成org.xml.sax.InputSource(xml的输入源)
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//实际加载方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
加载BeanDefinitions的实际方法。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//读取文件转成org.w3c.dom.Document(DOM树)
Document doc = doLoadDocument(inputSource, resource);
//注册BeanDefinitions
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
//省去又臭又长的catch.....
}
虽然这里并不能直接告诉你BeanDefinitionDocumentReader怎么读取DOC中的bean,然后注册到IOC容器中的(因为做了很多层的封装,这里展开来读的话,已经脱离XmlBeanDefinitionReader的功能范围了)。最后还是会通过getRegistry()方法拿到Registry属性然后注册BeanDefinition
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建BeanDefinitionDocumentReader(专门读取DOM树解析成BeanDefinition的类)
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//getRegistry()获取IOC容器(如:BeanFactory,Application)
//这里获取加载前数量
int countBefore = getRegistry().getBeanDefinitionCount();
//这里个方法做了很多doc的解析,最终会将BeanDefinitions加入到IOC容器中
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回加载数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
//这里读一下上面的createReaderContext(resource)方法
public XmlReaderContext createReaderContext(Resource resource) {
//这里传了个this,所以XmlReaderContext是里面是可以拿到IOC容器的
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
loadBeanDefinitions(Resource resource)最终会完成一下这些步骤: