XmlBeanDefinitionReader的几个关键方法讲解
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(); //注意resourcesCurrentlyBeingLoaded是一个ThreadLocal变量,获取当前线程的Set<EncodedResource>
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 {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());//真正加载BeanDefinition
}
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();
}
}
}
这个方法用于从指定的 XML 文件加载 bean 定义。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);//XML文件所定义的Document对象
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);
}
}
这个方法实际上从指定的 XML 文件加载 bean 定义。
@SuppressWarnings("deprecation")
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
注册包含在给定 DOM 文档中的 bean 定义,会被loadBeanDefinitions所调用,创建解析器类的新实例并调用
BeanDefinitionDocumentReader这个接口用于解析包含 Spring bean 定义的 XML 文档的 SPI。由 XmlBeanDefinitionReader 用于实际解析 DOM 文档。实现类是DefaultBeanDefinitionDocumentReader。
DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法根据“spring-beans”XSD解析bean定义,打开一个 DOM 文档;然后初始化在 beans 级别指定的默认设置 ;然后解析包含的 bean 定义。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
在给定的根 {@code } 元素中注册每个 bean 定义。
protected void doRegisterBeanDefinitions(Element root) {
//任何嵌套的 <beans> 元素都将导致此方法中的递归。
// 在为了正确传播和保留 <beans> default-* 属性,跟踪当前(父)委托,它可能为空。
//创造新的(子)委托,带有对父级的引用,用于回退目的,然后最终将 this.delegate 重置为其原始(父)引用。
//这种行为模拟了一堆委托,而实际上并不需要一个。
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
//经典的模板方法模式 preProcessXml(root);和postProcessXml(root);都是空实现,子类可以对其实现自定义扩展
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
BeanDefinitionParserDelegate用于解析 XML bean 定义的有状态委托类。供主解析器和任何扩展使用 {@link BeanDefinitionParser BeanDefinitionParsers}或{@link BeanDefinitionDecorator BeanDefinitionDecorators}。