解析条件和流程
当容器通过DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions方法解析元数据时,不仅可以解析4种内置的元数据(import、alias、bean、beans),还可以解析自定义元数据。
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
// 解析内置的<beans>根元素
……
}
// 前置处理
preProcessXml(root);
// 解析<beans>下各子元素
parseBeanDefinitions(root, this.delegate);
// 后置处理
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 解析内置元素
parseDefaultElement(ele, delegate);
} else {
// 解析自定义元素
delegate.parseCustomElement(ele);
}
}
}
} else {
// 解析自定义元素
delegate.parseCustomElement(root);
}
}
如上代码所示,元素的命名空间决定了解析流程:
- 命名空间为容器默认值,则调用parseDefaultElement方法按默认解析流程处理即可,具体处理细节请参考《Spring-IOC之BeanFactory启动流程》;
- 命名空间为自定义值,则DefaultBeanDefinitionDocumentReader认为当前遍历到的是一个自定义元素,此时将委派BeanDefinitionParserDelegate通过parseCustomElement方法来解析。
public class BeanDefinitionParserDelegate {
private final XmlReaderContext readerContext;
public BeanDefinitionParserDelegate(XmlReaderContext readerContext) {
Assert.notNull(readerContext, "XmlReaderContext must not be null");
this.readerContext = readerContext;
}
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
// 获取自定义元素的命名空间
String namespaceUri = getNamespaceURI(ele);
// NamespaceHandlerResolver将命名空间解析成对应的NamespaceHandler
NamespaceHandler handler = this.readerContext
.getNamespaceHandlerResolver().resolve(namespaceUri);
……
// NamespaceHandler将元数据解析成BeanDefinition
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
如上代码所示,解析自定义元素时需要两个重要的组件来参与,即命名空间处理解析器 (NamespaceHandlerResolver)和命名空间处理器(NamespaceHandler),其流程如下:
- BeanDefinitionParserDelegate获取当前自定义元素的命名空间;
- 利用NamespaceHandlerResolver将命名空间解析(resolve)成相应的NamespaceHandler;
- 利用NamespaceHandler最终将自定义元数据解析(parse)成BeanDefinition后返回结果。
命名空间处理解析器(NamespaceHandlerResolver)
在parseCustomElement方法中可看出,NamespaceHandlerResolver需要从XmlReaderContext(XML上下文读取器)中获取,而XmlReaderContext绑定的NamespaceHandlerResolver实例默认为DefaultNamespaceHandlerResolver,这是容器在启动期间由XmlBeanDefinitionReader通过registerBeanDefinitions方法开始解析时所创建,如下代码所示。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public int registerBeanDefinitions(Document doc, Resource resource)
throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 开始解析时创建XmlReaderContext
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
public XmlReaderContext createReaderContext(Resource resource) {
// 创建XmlReaderContext实例时绑定NamespaceHandlerResolver
return new XmlReaderContext(resource, this.problemReporter, this.eventListener