Spring 探秘 (一)-IoC容器的初始化过程(上)

简介: 严格来说,容器的初始化过程主要包括BeanDefinition的Resource定位BeanDefinition的载入和解析BeanDefinition在容器中的注册在初始化的过程当中,我们会看到一个又一个的方法被调用,换句话说,其实是通过调用一些方法来完成IoC容器初始化的.

严格来说,容器的初始化过程主要包括

  • BeanDefinition的Resource定位
  • BeanDefinition的载入和解析
  • BeanDefinition在容器中的注册

在初始化的过程当中,我们会看到一个又一个的方法被调用,换句话说,其实是通过调用一些方法来完成IoC容器初始化的.

refresh()方法,其实标志容器初始化过程的正式启动.

Spring之所以把这三个基本过程分开,并使用不同模块
如使用相应的ResourceLoaderBeanDefinitionReader等模块,是因为这样可以让用户更灵活地对这三个过程进行裁剪或扩展,定义出最适合自己的IoC容器的初始化过程.

1 BeanDefinition的Resource定位

BeanDefinition
从字面上理解,它代表着Bean的定义.
其实,它就是完整的描述了在Spring配置文件中定义的节点中的所有信息,包括各种子节点.
不太恰当地说,我们可以把它理解为配置文件中一个个<bean></bean>节点所包含的信息

ApplicationContext中,Spring已经为我们提供了一系列加载不同Resource的读取器的实现DefaultListableBeanFactory只是一个纯粹的IoC容器,需要为它提供特定的读取器才能完成这些功能.
但使用DefaultListableBeanFactory这种更底层的容器能提高定制IoC容器的灵活性.

至于常用的ApplicationContext见名知义,如

  • FileSystemXmlApplicationContext
  • ClassPathXmlApplicationContext
  • XmlWebApplicationContext
  • ...

下面将以FileSystemXmlApplicationContext为例,分析怎么完成Resource定位

img_7fe2bb1570492e1363527e4ddbc4bf87.png
ApplicationContext继承体系

从实现角度,我们近距离关心以 FileSystemXmlApplicationContext为核心的继承体系
img_c9a257092a13bd1d646b7e5458446b01.png

package org.springframework.context.support;

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

    public FileSystemXmlApplicationContext() {
    }

    // @param 父上下文
    public FileSystemXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }
 
    // 这个构造函数的configLocation包含BeanDefinition所在的文件路径
    public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

    // 这个构造函数允许configLocation包含多个BeanDefinition的文件路径
    public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, null);
    }

    
    // 这个构造函数允许configLocation包含多个BeanDefinition的文件路径的同时
    // 还允许指定自己的双亲IoC容器
    public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
        this(configLocations, refresh, null);
    }

    // 在对象的初始化过程中,调用refresh方法载入BeanDefinition,这个refresh启动了
    // BeanDefinition的载入过程,我们会在下面详解
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

    // 这是应用于文件系统的Resourse的实现,通过构造一个FileSystemResource得到一个在文件系统中定位的BeanDefinition
    // 这个getResourceByPath是在BeanDefinitionReader中被调用的
    // loadBeanDefinition采用了模板模式,具体的定位实现实际上是由各个子类完成的
    @Override
    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }
}

我们可以发现,在FileSystemXmlApplicationContext中不管调用哪个构造函数,最终都是会调用这个包含了refresh方法的构造函数,因此我们可以很容易得出结论:触发对BeanDefinition资源定位过程的refresh的调用是在FileSystemXmlApplicationContext的构造函数中启动的.

img_8144d48239974593a9195c13a24b074a.png

根据上图及 FileSystemXmlApplicationContext中含有 refresh()方法的构造函数的分析,可清楚地看到整个 BeanDefinition资源定位的过程.
该过程最初是由 refresh()触发,而 refresh()的调用是在 FileSystemXmlApplicationContext的构造函数中启动的,大致调用过程如下图
img_9921316eb9fb53684433d8ce9517b2d8.png

看了调用过程,我们可能好奇这个 FileSystemXmlAppplicationContext在什么地方定义了 BeanDefinition的读入器 BeanDefinitionReader的呢?
关于这个读入器的配置,我们到其基类 AbstractRefreshableApplicationContextrefreshBeanFactory()方法看看
img_b99f66d42816aa6ca68e551f7838a6d4.png

刚才我们提到, refresh()的调用是在 FileSystemXmlApplicationContext的构造函数中启动的
而这个 refresh()又是从 AbstractApplicationContext继承而来
因此,结合前面方法时序图知 refreshBeanFactory()FileSystemXmlApplicationContext构造函数中的 refresh()调用.
在这个方法( refreshBeanFactory())中,通过 createBeanFactory()构建了一个容器供 ApplicationContext使用.
这个容器就是前面我们提到的 DefaultListableBeanFactory,同时它还启动了 loadBeanDefinition()来载入 BeanDefinition,这里和以编程式使用IoC容器的过程很相似
AbstractRefreshableApplictionContext中,这里是使用 BeanDefinitionReader载入Bean定义的地方,因为允许有多种载入方式,这里通过一个抽象函数把具体的实现委托给子类完成

从前面的方法调用栈可以发现refreshBeanFactory方法中调用的loadBeanDefinitions方法其实最终是调用AbstractBeanDefinitionReader里面的loadBeanDefinitions方法

img_6cf892bb27ea3a3663f9ac8b4b1b3c4b.png

对于取得 Resource的具体过程,我们来看看 DefaultResourceLoader怎样完成
img_c7f27997071cbeb030cd9566bc359f0a.png

上图中 getResourcePath()将会被 FileSystemXmlApplicationContext实现.
该方法返回的是一个 FileSystemResource对象,通过这个对象,Spring可以进行相关的I/O操作,完成 BeanDefinition的定位.

如果是其他的ApplicationContext,那么会对应生成其他种类的Resource,比如ClassPathResourceServletContextResource

所以BeanDefinition的定位到这里就完成了.
BeanDefinition定位完成的基础上,就可以通过返回的Resource对象进行BeanDefinition的载入了.
在定位过程完成后,为BeanDefinition的载入创造了I/O操作的条件,但具体的数据还没有开始读入.这些读入将在下面介绍的BeanDefinition的载入和解析中来完成.

目录
相关文章
|
10月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
10月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
809 2
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
328 1
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
XML Java 数据格式
Spring IoC容器初始化过程(xml形式)
Spring IoC容器初始化过程(xml形式)
355 0
|
XML Java 数据格式
Spring5源码(15)-IoC容器启动过程简析及XmlBeanFactory初始化
Spring5源码(15)-IoC容器启动过程简析及XmlBeanFactory初始化
345 1
|
XML 设计模式 Java
「推荐收藏!」【Spring源码探究】(一)IOC容器初始化🏅彻底让你明白运行原理和源码流程
「推荐收藏!」【Spring源码探究】(一)IOC容器初始化🏅彻底让你明白运行原理和源码流程
360 0
「推荐收藏!」【Spring源码探究】(一)IOC容器初始化🏅彻底让你明白运行原理和源码流程
|
XML Java 数据格式
Spring源码阅读-IOC容器初始化过程
Spring IOC容器的初始化过程:Resource定位,BeanDefinition载入,向IOC容器注册BeanDefinition。整个过程由refresh()方法触发,三个过程由不同的模块完成,使用户更加灵活的对这三个过程剪裁和扩展。
552 0
|
XML JavaScript Java
Spring IoC容器初始化过程(xml形式)
Resource是Spring中用于封装I/O操作的接口,在创建Spring的容器的时候,会根据xml对应配置的类型,加载不同的数据类型
186 0
|
XML Java 测试技术
面试官:说说Spring IoC容器初始化主体流程
一、Spring IoC的容器体系 IoC容器是Spring的核心模块,是抽象了对象管理、依赖关系管理的框架解决方案。Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从的一套原则,具体的容器实现可以增加额外的功能,比如我们常用到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等一系列的内容, AnnotationConfigApplicationContext 则是包含了注解解析等一系列的内容。
面试官:说说Spring IoC容器初始化主体流程