Spring5源码(15)-IoC容器启动过程简析及XmlBeanFactory初始化

简介: Spring5源码(15)-IoC容器启动过程简析及XmlBeanFactory初始化


上篇分析了Spring对资源文件的加载过程,接下来我们就要开始分析Spring的IoC容器了(基于XmlBeanFactory)。

1.IoC容器启动过程简析

注意:以BeanFactory为基础的IoC容器在启动完成之后,并不会立刻实例化配置文件中的bean,首次实例化发生在我们第一次向容器索取的过程中。如果IoC容器这个概念生涩难懂、或者让人觉得有些深奥的话,那么就理解为一个类的实例化即可,只不过这个类的实例化过程,比较复杂而已!

在上一篇也介绍了IoC容器的启动过程为:加载资源文件、解析资源文件、注册BeanDefinition,我们再来看一个更为详细的流程图(该流程图只列举了比较重要的步骤)。


image.png

总而言之,就是将xml文件转换为SpringIoC容器的内部表示。

2. XmlBeanFactory初始化

打开我们之前复习Spring知识点的测试类,以xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("v2/day01.xml"));为切入点。打开XmlBeanFactory类。

public class XmlBeanFactory extends DefaultListableBeanFactory {
    // 实例化XmlBeanDefinitionReader对象
    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
    /**
     * 通过指定Resource对象创建XmlBeanFactory实例
     */
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }
    /**
     * 通过指定Resource对象和父BeanFactory创建XmlBeanFactory实例
     */
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        // 依次向上实例化父类构造器
        super(parentBeanFactory);
        // 解析xml配置文件,将其转换为IoC容器的内部表示
        this.reader.loadBeanDefinitions(resource);
    }
}

先来分析加载bean之前的准备工作,XmlBeanFactory父类初始化和XmlBeanDefinitionReader初始化。

2.1 父类初始化

通过XmlBeanFactory的继承关系依次调用各个父类的构造方法:

flowchat
st=>start: 开始
e=>end: 结束
op1=>operation: 初始化AbstractBeanFactory
op2=>operation: 初始化AbstractAutowireCapableBeanFactory
op3=>operation: 初始化DefaultListableBeanFactory
op4=>operation: 初始化XmlBeanFactory 
st->op1->op2->op3->op4->e

该过程初始化的信息很多,我们选择其中比较重要的几点做下介绍。

  • 忽略指定接口的自动装配功能

public AbstractAutowireCapableBeanFactory() {
    super();
    // 忽略指定接口的自动装配功能
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
}

忽略指定接口的自动装配功能:如ClassA引用了ClassB,那么当Spring在获取ClassA的实例时,如果发现ClassB还没有被初始化,那么Spring会自动初始化ClassB。但是如果ClassB实现了BeanNameAware接口的话,则Spring不会自动初始化ClassB,这就是忽略指定接口的自动装配。

2.2 初始化XmlBeanDefinitionReader

将xml文件中的配置转换为IoC内部的表示就是由XmlBeanDefinitionReader来完成的。XmlBeanDefinitionReader继承了AbstractBeanDefinitionReader类,我们来其初始化都完成了哪些操作。

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;
    // Determine ResourceLoader to use.
    // 1、确定ResourceLoader使用。
    if (this.registry instanceof ResourceLoader) {
        this.resourceLoader = (ResourceLoader) this.registry;
    }
    else {
        this.resourceLoader = new PathMatchingResourcePatternResolver();
    }
    // Inherit Environment if possible
    // 2、如果环境可继承则继承registry的环境,否则重新创建环境
    if (this.registry instanceof EnvironmentCapable) {
        this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
    }
    else {
        this.environment = new StandardEnvironment();
    }
}
  • 1、确定ResourceLoader使用。该方法的核心就是确定当前使用的类加载器

public PathMatchingResourcePatternResolver() {
    this.resourceLoader = new DefaultResourceLoader();
}

public DefaultResourceLoader() {
    this.classLoader = ClassUtils.getDefaultClassLoader();
}

public static ClassLoader getDefaultClassLoader() {
    ClassLoader cl = null;
    try {
        //优先获取线程上下文类加载器
        cl = Thread.currentThread().getContextClassLoader();
    }
    catch (Throwable ex) {
        // Cannot access thread context ClassLoader - falling back...
    }
    if (cl == null) {
        // No thread context class loader -> use class loader of this class.
        // 获取当前类的类加载器
        cl = ClassUtils.class.getClassLoader();
        if (cl == null) {
            // getClassLoader() returning null indicates the bootstrap ClassLoader
            try {
                //获取SystemClassLoader
                cl = ClassLoader.getSystemClassLoader();
            }
            catch (Throwable ex) {
                // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
            }
        }
    }
    return cl;
}
  • 2、如果环境可继承则继承registry的环境,否则重新创建环境
    系统环境包括了系统环境属性(主机变量信息)、JVM系统环境属性(JDK版本,JDK目录等)、默认激活节点、属性解析器等。

StandardEnvironment初始化

public class StandardEnvironment extends AbstractEnvironment {
    /** 系统环境属性 System environment property source name: {@value}. */
    public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
    /** JVM系统环境属性 JVM system properties property source name: {@value}. */
    public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
    /**
     * Customize the set of property sources with those appropriate for any standard
     * Java environment:
     * <ul>
     * <li>{@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME}
     * <li>{@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}
     * </ul>
     * <p>Properties present in {@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME} will
     * take precedence over those in {@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}.
     * @see AbstractEnvironment#customizePropertySources(MutablePropertySources)
     * @see #getSystemProperties()
     * @see #getSystemEnvironment()
     */
    @Override
    protected void customizePropertySources(MutablePropertySources propertySources) {
        // 主要通过System类来获取信息
        // 获取系统环境属性并加入到propertySources中
        propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
        // 获取JVM系统环境属性并加入到propertySources中
        propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
    }
}

AbstractEnvironment初始化

private final MutablePropertySources propertySources = new MutablePropertySources();
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
public AbstractEnvironment() {
    customizePropertySources(this.propertySources);
}




目录
相关文章
|
2天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
22天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
41 2
|
21小时前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
16天前
|
监控 NoSQL 时序数据库
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
156 77
|
25天前
|
监控 Docker 容器
在Docker容器中运行打包好的应用程序
在Docker容器中运行打包好的应用程序
|
3天前
|
存储 Kubernetes 开发者
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
Docker 是一种开源的应用容器引擎,允许开发者将应用程序及其依赖打包成可移植的镜像,并在任何支持 Docker 的平台上运行。其核心概念包括镜像、容器和仓库。镜像是只读的文件系统,容器是镜像的运行实例,仓库用于存储和分发镜像。Kubernetes(k8s)则是容器集群管理系统,提供自动化部署、扩展和维护等功能,支持服务发现、负载均衡、自动伸缩等特性。两者结合使用,可以实现高效的容器化应用管理和运维。Docker 主要用于单主机上的容器管理,而 Kubernetes 则专注于跨多主机的容器编排与调度。尽管 k8s 逐渐减少了对 Docker 作为容器运行时的支持,但 Doc
27 5
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
|
9天前
|
关系型数据库 应用服务中间件 PHP
实战~如何组织一个多容器项目docker-compose
本文介绍了如何使用Docker搭建Nginx、PHP和MySQL的环境。首先启动Nginx容器并查看IP地址,接着启动Alpine容器并安装curl测试连通性。通过`--link`方式或`docker-compose`配置文件实现服务间的通信。最后展示了Nginx配置文件和PHP代码示例,验证了各服务的正常运行。
29 3
实战~如何组织一个多容器项目docker-compose
|
18天前
|
数据建模 应用服务中间件 nginx
docker替换宿主与容器的映射端口和文件路径
通过正确配置 Docker 的端口和文件路径映射,可以有效地管理容器化应用程序,确保其高效运行和数据持久性。在生产环境中,动态替换映射配置有助于灵活应对各种需求变化。以上方法和步骤提供了一种可靠且易于操作的方案,帮助您轻松管理 Docker 容器的端口和路径映射。
60 3
|
25天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
64 7
|
25天前
|
存储 Prometheus 监控
Docker容器内进行应用调试与故障排除的方法与技巧,包括使用日志、进入容器检查、利用监控工具及检查配置等,旨在帮助用户有效应对应用部署中的挑战,确保应用稳定运行
本文深入探讨了在Docker容器内进行应用调试与故障排除的方法与技巧,包括使用日志、进入容器检查、利用监控工具及检查配置等,旨在帮助用户有效应对应用部署中的挑战,确保应用稳定运行。
32 5