我们继续回到主线任务:
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions /** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 一般来说,我们的根节点都是<beans>,这个是默认namespace的 if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); // 遍历xml <beans>下的每个元素 for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; // 判断元素是不是默认命名空间的,比如<bean>是,<context:component-scan>不是 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { //<context:component-scan>,<aop:xxxx>走这边 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }这里,判断一个元素是不是默认命名空间,具体怎么做的呢:
BeanDefinitionParserDelegate#isDefaultNamespace(org.w3c.dom.Node) public boolean isDefaultNamespace(Node node) { //调用重载方法 return isDefaultNamespace(getNamespaceURI(node)); } public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans"; public boolean isDefaultNamespace(String namespaceUri) { return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri)); } 默认namespace时的逻辑 DefaultBeanDefinitionDocumentReader#parseDefaultElement private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }第一次发现,原来默认命名空间下,才这么几个元素:
import、alias、bean、(NESTED_BEANS_ELEMENT)beans
具体的解析放到下讲,这讲内容已经够多了。
非默认namespace时的逻辑主要是处理:aop、context等非默认namespace。
BeanDefinitionParserDelegate public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); // 这里,就和前面串起来了,根据namespace找handler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }我们挑一个大家最熟悉的org.springframework.context.config.ContextNamespaceHandler,大家先看看:
public class ContextNamespaceHandler extends NamespaceHandlerSupport { public void init() { // 这个也熟悉吧 registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); // 这个熟悉吧 registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser()); registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser()); } }总之,到了这里,就是根据具体的元素,找对应的处理器了。这些都后面再说了。内容太多了。
总结大家可以回头再去看看第二章的整体流程,会不会清晰一些了呢?
主要是几个核心类:
XmlBeanDefinitionReader
BeanDefinitionDocumentReader
XmlReaderContext
namespaceHandlerResolver
BeanDefinitionParserDelegate
内容有点多,大家不要慌,我们后面还会进一步讲解的。觉得有帮助的话,点个赞哦。