阅读 107

【spring源码】xml解析(上)

引题

spring框架最早是基于配置文件开发,后来引入注解的方式。回想下我最初使用spring框架的方式:

  1. 新建一个maven工程,引入spring相关jar包。

  2. 创建一个配置文件“spring.xml”。

  3. 创建测试类。

image.png

image.png

image.png

由此,spring框架创建了一个Man的实例。 可以想到,spring是根据“spring.xml”配置文件 中的< bean >标签创建了Man实例,下面通过源码看下具体的解析流程。

主流程解析

image.png

类的继承关系

ClassPathXmlApplicationContext 类

image.png

image.png 142 行:记录下配置文件名称 “spring.xml”。
143 行 :主流程

AbstractApplicationContext 类

@Override // spring源码的大门,你准备好了么。 public void refresh() throws BeansException, IllegalStateException {         synchronized (this.startupShutdownMonitor) {                 // Prepare this context for refreshing.                 prepareRefresh();                 // Tell the subclass to refresh the internal bean factory.                 // xml 解析                 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();                 // Prepare the bean factory for use in this context.                 prepareBeanFactory(beanFactory);                 try {                         // Allows post-processing of the bean factory in context subclasses.                         postProcessBeanFactory(beanFactory);                         // Invoke factory processors registered as beans in the context.                         invokeBeanFactoryPostProcessors(beanFactory);                         // Register bean processors that intercept bean creation.                         registerBeanPostProcessors(beanFactory);                         // Initialize message source for this context.                         initMessageSource();                         // Initialize event multicaster for this context.                         initApplicationEventMulticaster();                         // Initialize other special beans in specific context subclasses.                         onRefresh();                         // Check for listener beans and register them.                         registerListeners();                         // Instantiate all remaining (non-lazy-init) singletons.                         finishBeanFactoryInitialization(beanFactory);                         // Last step: publish corresponding event.                         finishRefresh();                 }                 catch (BeansException ex) {                         if (logger.isWarnEnabled()) {                                 logger.warn("Exception encountered during context initialization - " +                                                 "cancelling refresh attempt: " + ex);                         }                         // Destroy already created singletons to avoid dangling resources.                         destroyBeans();                         // Reset 'active' flag.                         cancelRefresh(ex);                         // Propagate exception to caller.                         throw ex;                 }                 finally {                         // Reset common introspection caches in Spring's core, since we                         // might not ever need metadata for singleton beans anymore...                         resetCommonCaches();                 }         } 复制代码

image.png 523 行:主流程

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 方法总结: 1. 创建了BeanFactory对象。 2. xml解析    --默认标签解析:<bean>...    --自定义标签解析:<context:component-scan>      复制代码

image.png

AbstractRefreshableApplicationContext 类

image.png image.png

127 行:创建bean工厂
129 行:设置是否可以循环依赖
130 行:主流程,解析xml,加载BD(BeanDefinition) 点击进入 AbstractXmlApplicationContext 类
131 行:赋值给 AbstractRefreshableApplicationContext 类的属性。

AbstractXmlApplicationContext 类

image.png 83 行:委托模式 创建xml解析器。使用 XmlBeanDefinitionReader 解析xml配置文件。
94 行:主流程,加载BD(入参为XmlBeanDefinitionReader)

image.png 126 行:获取到需要加载的配置文件,最开始设置的 “spring.xml”
128 行:主流程

image.png image.png 223 行:将配置文件转换为 Resource 对象(流的方式)
224 行:开始调用 XmlBeanDefinitionReader类 的加载BD方法

image.png 188 行:模板模式,调到子类中的方法,这里调到 XmlBeanDefinitionReader 类

XmlBeanDefinitionReader 类

image.png 310 行:将 Resource 对象包装成 EncodedResource
333 行:获取到resource对象中的流对象
338 行:主流程

image.png 390 行:把inputSource 封装成Document文件对象,这是jdk的API
391 行:主流程。根据 Document 对象获取到里面的标签封装成 BD

image.png 509 行:委托模式 委托 BeanDefinitionDocumentReader这个类进行 Document 对象的解析
511 行:主流程

DefaultBeanDefinitionDocumentReader 类

image.png image.png 121 行:入参为root节点
129 行:创建一个 BeanDefinitionParserDelegate 对象
148 行:解析之前调用,对root节点进行修饰。默认实现逻辑为空,可自定义
149 行:主流程。解析BD
148 行:解析之前调用,对root节点进行修饰。默认实现逻辑为空,可自定义。

image.png 该方法逻辑总结: 根据根节点获取到xml文件中配置的子节点集合进行遍历,判断节点类型(默认标签/自定义标签)并分别进行解析。

170 行:获取到根标签的子标签列表
175 行:判断是默认标签还是自定义标签
176 行:默认标签解析
179 行:自定义标签解析

到此,我们已经从配置文件中获取到了标签,接下来就是两种标签具体解析的逻辑。

总结

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); 复制代码

这行代码执行时,spring会根据入参找到配置文件,然后通过流的方式解析该文件并获取到文件里面的节点信息,再根据节点的类型分别进行解析(就是将标签转换为BeanDefinition)。


作者:一支野菊花
链接:https://juejin.cn/post/7023608217984827422


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐