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);}}复制代码
- 文件系统(02):基于SpringBoot管理Xml和CSV
- SpringBoot2.x入门到项目实战课程系列(第二章)
- SpringBoot集成Mybatis
- 大牛深入解析SpringBoot核心运行原理和运作原理源码
- SpringBoot写后端接口,看这一篇就够了
- 9款游戏13块SSD:测试固态硬盘对游戏加载速度影响有多大?
- Spring Boot 中 @EnableX 注解的驱动逻辑
- SpringBoot2.x入门到项目实战课程系列(第五章)
- SpringBoot整合JWT+Shiro
- 14 个 SpringMVC顶级技巧,随时用随时爽