Spring Bean加载流程分析(通过 XML 方式加载)( 七 )
@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;//doc.getDocumentElement() 获取文档中的 element 元素doRegisterBeanDefinitions(doc.getDocumentElement());}protected void doRegisterBeanDefinitions(Element root) {// 任何嵌套的标签在这个方法中将会导致递归// Any nestedelements will cause recursion in this method. In// order to propagate and preservedefault-* attributes correctly,// keep track of the current (parent) delegate, which may be null. Create// the new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createDelegate(getReaderContext(), root, parent);// ... 省略部分代码preProcessXml(root);parseBeanDefinitions(root, this.delegate);postProcessXml(root);this.delegate = parent;}复制代码
从 doRegisterBeanDefinitions 中的注释我们知道 ,
- 该方法可能会导致递归 , 如果我们在 applicationContext.xml 配置了引用其他
- 该方法使用了典型的 delegate 。 就是我自己要做某件事 , 我自己不做 , 让其他类帮我去做 。
文章插图
这是一种典型的模板方法设计模式 。 可以看到该方法被定义成了 protected , 留作子类去实现 。 核心的解析逻辑在 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) {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);}}复制代码
该方法解析了文档最顶层的标签元素 , 例如 bean , import 等等 , 除了解析 Spring 规定的标签节点外 , 还解析了自定义的标签元素 。 自定义的标签我们很少用到 , 着重看一下解析默认的标签元素 。 跟到 parseDefaultElement 中看看 。private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {// IMPORT_ELEMENT = "import"if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}// ALIAS_ELEMENT = "alias"else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}// BEAN_ELEMENT = "bean"else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}// NESTED_BEANS_ELEMENT = "beans"else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recurse 递归doRegisterBeanDefinitions(ele);}}复制代码
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- FlinkSQL 动态加载 UDF 实现思路
- 基于Spring+Angular9+MySQL开发平台
- 网络比15年前更慢错误更多?开发者加载了100万个网站实测
- 别不拿GateWay当回事,SpringCloud告诉你错了
- web 安全之 Spring Security 入门教程
- Spring Application实例化流程和构造方法参数
- SpringBoot常用注解
- 阿里爆款SpringBoot项目实战PDF+源码+视频分享
- Firefox 83将默认启用Warp更新:大幅提升响应时间和加载速度
- SpringCloud下skywalking的快速入门