SpringIOC源码解析(7)—— xml配置的资源定位、加载、解析、注册全链路分析

简介: 调用过程复现:在DefaultListableBeanFactory的registerBeanDefinition里打上断点,运行Entrance,观察调用栈:

文章目录


调用过程复现:

在DefaultListableBeanFactory的registerBeanDefinition里打上断点,运行Entrance,观察调用栈:


9.png


Entrance源码:阅读Spring源码第一步:源码编译与创建调试入口

注册是从主函数开始的:


10.png


之后进入到FileSystemXmlApplicationContext的构造函数:

public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
   this(new String[] {configLocation}, true, null);
}

又调用了另外一个构造函数:


public FileSystemXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {
   super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}


对应变量的值:


11.png


其中configLocations是个数组,所以猜测最后调用了加载多个资源的方法。

又调用refresh()方法进行容器的初始化,此时又来到AbstractApplicationContext的refresh方法里:

12.png


又调用了obtainFreshBeanFactory方法,跳进去会发现它是调用了子类的refreshBeanFactory方法,以刷新子类的容器

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();
   return getBeanFactory();
}

再往前进会发现实现refreshBeanFactory方法的是AbstractRefreshableApplicationContext类:


13.png


先创建了容器实例,再将实例传入到loadBeanDefinitions里

进入到loadBeanDefinitions,该方法是由AbstractXmlApplicationContext实现的:


protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   // 为给定的BeanFactory创建一个新的XmlBeanDefinitionReader
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
   // Configure the bean definition reader with this context's
   // resource loading environment.
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   // 将容器本身"献祭"
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
   // Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.
   initBeanDefinitionReader(beanDefinitionReader);
   loadBeanDefinitions(beanDefinitionReader);
}


14.png


先是定义了XmlBeanDefinitionReader的实例变量beanDefinitionReader,变量的构造函数便是传入的DefaultListableBeanFactory实例;


此外beanDefinitionReader还给自己的ResourceLoader设置上FileSystemXmlApplicationContext;


因此FileSystemXmlApplicationContext实例和DefaultListableBeanFactory实例便是通过beanDefinitionReader对象串联到了一起,这也就表明了打通了资源加载和BeanDefinition之间的通路。


再前进一步就是加载资源的配置流程了(AbstractXmlApplicationContext.java):


protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }
   String[] configLocations = getConfigLocations();   // 从这里继续进
   if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
   }
}


进入到getConfigLocations方法里:


@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
   Assert.notNull(locations, "Location array must not be null");
   int count = 0;
   for (String location : locations) {
      count += loadBeanDefinitions(location);
   }
   return count;
}

这里就是根据location来逐个调用loadBeanDefinitions去加载。

继续进到loadBeanDefinitions方法里:


15.png


可以看到确实是使用了ResourcePatternResolver来进行加载的,和上面的推断一样是用可以同时加载多个资源的。

再进入两层到loadBeanDefinitions方法里:


16.png


发现到了对resource包裹上EncodedResource这一步

再进入一层,此时就是对资源进行编码处理了:


17.png


进入到实际干活的doLoadBeanDefinitions中:

18.png


这里面主要就是将xml解析成document对象了,解析完成之后就进入到注册阶段

注册阶段:


18.png


先是将Document对象解析成一个个的BeanDifinitions

19.png


继续进入到doRegisterBeanDefinitions里:


20.png


就会发现这里开始解析BeanDefinition了,并且此处的delegate对象是BeanDefinitionParserDelegate对象

之后就会进入解析逻辑里面进行BeanDefinition的解析了:


21.png


因为我们遵循的是xml定义的规范,所以会执行parseDefaultElement方法,方法之前已经分析过了,这一步会递归执行多次。


再往深一点就会看到调用了delegate的parseBeanDefinitionElement方法区解析出包含了BeanDefinition实例的BeanDefinitionHolder包装实例


22.png

之后就来到了SpringIOC源码解析(5)—— BeanDefinition的注册中的BeanDefinition的注册环节了,最终将BeanDefinition实例注册到容器里,同时,如果BeanDefinition先前已经注册过了,就需要清空先前的注册信息,如果是单例,将先前已经创建出来的bean实例给清除掉,因为bean实例赖以生存的BeanDefinition已经改变了。


相关文章
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
654 4
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
XML 前端开发 Java
讲解SSM的xml文件
本文详细介绍了SSM框架中的xml配置文件,包括springMVC.xml和applicationContext.xml,涉及组件扫描、数据源配置、事务管理、MyBatis集成以及Spring MVC的视图解析器配置。
438 1
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
Android开发 开发者
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
本文详细介绍了如何通过自定义 `attrs.xml` 文件实现 Android 自定义 View 的属性配置。以一个包含 TextView 和 ImageView 的 DemoView 为例,讲解了如何使用自定义属性动态改变文字内容和控制图片显示隐藏。同时,通过设置布尔值和点击事件,实现了图片状态的切换功能。代码中展示了如何在构造函数中解析自定义属性,并通过方法 `setSetting0n` 和 `setbackeguang` 实现功能逻辑的优化与封装。此示例帮助开发者更好地理解自定义 View 的开发流程与 attrs.xml 的实际应用。
468 2
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
|
XML Java 数据格式
java创建xml文件内容
java创建xml文件内容
257 0
|
Java Maven
maven项目的pom.xml文件常用标签使用介绍
第四届人文,智慧教育与服务管理国际学术会议(HWESM 2025) 2025 4th International Conference on Humanities, Wisdom Education and Service Management
1418 8
|
XML JavaScript Java
java与XML文件的读写
java与XML文件的读写
290 3

热门文章

最新文章

推荐镜像

更多
  • DNS