一文彻底弄懂Spring Boot的启动过程

news/2024/11/8 21:51:28/文章来源:https://www.cnblogs.com/lgx211/p/18535984

一,Spring Boot启动过程

1. 启动入口

Spring Boot 应用的启动入口通常是一个包含 @SpringBootApplication 注解的主类,并调用 SpringApplication.run() 方法。@SpringBootApplication 是一个复合注解,包含了 @Configuration@EnableAutoConfiguration@ComponentScan,从而开启了自动配置和组件扫描。

源码路径在 SpringApplication 类的 run() 方法:

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return new SpringApplication(primarySource).run(args);
}

这个入口主要做了以下几件事情:

  1. 创建 SpringApplication 实例:初始化 Spring Boot 环境。
  2. 初始化环境和监听器:设置启动的 Environment,并且添加 ApplicationListener 监听器。
  3. 准备和刷新 Spring 上下文:通过 prepareContextrefreshContext 方法进行上下文环境的准备和刷新。

2. 创建 SpringApplication 实例

SpringApplication 的构造方法中,Spring Boot 解析应用的启动模式(例如是 Web 应用、Servlet 应用或是普通应用),并初始化应用的上下文类型。Spring Boot 的不同上下文类型包括 AnnotationConfigApplicationContext(非 Web 应用)和 AnnotationConfigServletWebServerApplicationContext(Web 应用)。

3. 初始化 Environment 和监听器

接下来,Spring Boot 会初始化 ConfigurableEnvironment,这个环境中包含了系统的属性、环境变量、配置文件等数据,作为后续加载 Bean 定义和初始化的基础。

同时,Spring Boot 也会初始化一系列的 ApplicationListener,用于监听和处理应用启动过程中的事件,比如 ApplicationEnvironmentPreparedEventApplicationPreparedEvent 等。

4. 加载配置类并触发自动配置

Spring Boot 使用 @EnableAutoConfiguration 注解触发自动配置,核心实现是在 AutoConfigurationImportSelector 中加载 META-INF/spring.factories 配置文件,文件中列出了许多自动配置类(如 DataSourceAutoConfigurationJpaRepositoriesAutoConfiguration 等),根据条件(例如某些 Bean 是否存在、某些属性是否被配置等)加载相应的自动配置。

5. 加载并注册 Bean

refreshContext() 方法中,Spring Boot 调用 refresh() 方法,这一步骤中完成了 BeanFactory 的初始化和 BeanPostProcessor 的注册,并解析 @Component@Service@Repository 等注解标注的 Bean 定义,将它们注册到 BeanFactory 中。

在源码层面,refresh() 方法中,invokeBeanFactoryPostProcessorsregisterBeanPostProcessors 这两个方法是关键,分别用于执行所有 BeanFactoryPostProcessorBeanPostProcessor,确保 Bean 的生命周期正确管理。

6. Web 环境中的嵌入式容器启动

在 Web 应用中,Spring Boot 会启动嵌入式 Web 容器(如 Tomcat 或 Jetty)。Spring Boot 默认通过 ServletWebServerApplicationContext 启动内嵌的 Web 服务器。在 refresh() 的最后,会启动嵌入式容器,将应用作为 Web 应用发布。

7. 执行 ApplicationRunner 和 CommandLineRunner

Spring Boot 启动完成后,会扫描并执行所有实现了 ApplicationRunnerCommandLineRunner 接口的 Bean。它们可以用于在启动后执行自定义逻辑。

8. 发布应用启动完成事件

最后,Spring Boot 发布 ApplicationReadyEvent 事件,通知所有监听器应用已启动完成。至此,Spring Boot 应用正式启动完成,可以接收 HTTP 请求或执行其他任务。

二、Spring Boot 启动过程的架构设计

在 Spring Boot 应用启动的过程中,SpringApplication.run() 是最常用的启动方式。通过这个方法,Spring Boot 为开发者屏蔽了大量复杂的初始化细节,我们只需提供主启动类的入口和简单的配置信息即可启动整个应用。

下面我们从源码入手,分步骤分析 SpringApplication.run 进行的操作。

1,SpringApplication.run() 的详细流程

SpringApplication.run 主要完成以下几大步骤:

  1. 初始化 SpringApplication 实例

    该实例负责整个 Spring Boot 应用的启动过程,通过判断应用类型和设置环境变量为后续配置加载和应用上下文创建提供基础。核心方法为 SpringApplication#prepareEnvironmentSpringApplication#createApplicationContext

  2. 创建应用上下文并刷新上下文

    SpringApplication 将根据应用类型来创建不同的 ApplicationContext(如 AnnotationConfigApplicationContextServletWebServerApplicationContext),并将所有 Bean 装载到上下文中。

  3. 加载环境配置

    Spring Boot 会基于开发环境或生产环境加载不同的配置文件。核心是 ConfigFileApplicationListener 监听配置事件,解析应用配置文件(application.propertiesapplication.yml)并装配到应用上下文的 Environment 对象中。

  4. 启动嵌入式容器

    如果是 Web 应用,Spring Boot 会启动内嵌的服务器(如 Tomcat、Jetty 或 Undertow),并将 DispatcherServlet 注册到服务器中。

2,SpringApplication 核心设计类

在源码层面,SpringApplication 是启动过程中的关键类。它通过构造函数和 run() 方法完成了以下工作:

public class SpringApplication {public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = deduceWebApplicationType();this.setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));this.setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}public ConfigurableApplicationContext run(String... args) {// 初始化阶段StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);context = createApplicationContext();prepareContext(context, environment, listeners, applicationArguments);refreshContext(context);afterRefresh(context, applicationArguments);listeners.started(context);callRunners(context, applicationArguments);} catch (Exception ex) {handleRunFailure(context, listeners, ex);throw new IllegalStateException(ex);} finally {stopWatch.stop();}return context;}
}

源码揭示了 SpringApplication 的核心功能在于配置监听器、加载环境、创建上下文等几个方面。通过 deduceWebApplicationType() 方法判断 Web 应用类型,为接下来的 ApplicationContext 选择提供了依据。这种设计实现了启动流程的高度定制和灵活适应性。


三、启动过程中的关键组件及设计模式

Spring Boot 的启动流程涉及到多个设计模式,这些模式不仅提升了代码的可读性和灵活性,也确保了在不同的业务场景下能够快速地调整启动行为。

1,ApplicationContext 和 ConfigurableEnvironment

ApplicationContext 是 Spring 框架的核心概念之一,提供了 IoC 容器的实现和应用上下文的管理。在 Spring Boot 中,ApplicationContext 包含了所有的 Bean,并提供了应用与外部环境的接口,如 ConfigurableEnvironment,用于管理应用的环境配置和属性。

ApplicationContext 的核心设计

ApplicationContext 是一个高度抽象的接口,它有多个具体实现,如 AnnotationConfigApplicationContextServletWebServerApplicationContext。Spring Boot 的 SpringApplication 会根据应用的类型选择合适的 ApplicationContext 实现,并对其进行配置和初始化:

  • 非 Web 应用:使用 AnnotationConfigApplicationContext 加载配置类和 Bean。
  • Web 应用:使用 ServletWebServerApplicationContext,并加载嵌入式 Web 容器配置。

这种设计模式提升了 ApplicationContext 的适配性,使其可以灵活适应各种不同类型的应用。

ConfigurableEnvironment 环境配置的加载

ConfigurableEnvironment 提供了应用的环境信息,包括系统属性、环境变量以及外部化的配置文件内容。在 Spring Boot 启动过程中,ConfigurableEnvironment 会在 prepareEnvironment() 方法中被初始化。

ConfigurableEnvironment 中,属性源的优先级管理极大地提升了配置的灵活性。Spring Boot 根据不同的 PropertySource(如 application.properties、环境变量、命令行参数等),提供优先级管理,这样使得在复杂环境下也能灵活覆盖配置。

2,ApplicationListener 事件驱动模型

ApplicationListener 是 Spring 框架中事件驱动机制的实现,Spring Boot 使用该机制管理启动过程中各类重要事件。以下是常见的启动事件:

  • ApplicationStartingEvent:在 SpringApplication.run() 开始时触发。
  • ApplicationEnvironmentPreparedEvent:在 Environment 准备好之后触发。
  • ApplicationPreparedEvent:在上下文加载完成之前触发。
  • ApplicationStartedEvent:在上下文刷新完成之后触发。
  • ApplicationReadyEvent:应用启动完成时触发。

事件驱动模型允许开发者在应用启动的各个阶段进行自定义操作,极大增强了扩展性和灵活性。

3,依赖注入和条件配置加载机制

Spring Boot 中自动配置依赖于条件加载机制,核心在于 @Conditional 系列注解,比如 @ConditionalOnClass@ConditionalOnMissingBean 等。这些注解允许 Spring Boot 根据实际情况有选择性地加载配置:

@Configuration
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration {// 数据源自动配置逻辑
}

这种条件注入模式通过按需加载 Bean,有效减少了资源的浪费。此设计模式也让 Spring Boot 能够快速适应不同的环境和依赖场景,避免不必要的 Bean 被加载。


四、自动配置的实现机制

Spring Boot 通过 @EnableAutoConfiguration 启动自动配置功能,它的底层实现机制是 AutoConfigurationImportSelectorSpringFactoriesLoader,其中 SpringFactoriesLoader 会扫描 META-INF/spring.factories 文件加载自动配置类。

1,SpringFactoriesLoader 详解

Spring Boot 自动配置的一个核心机制是 SpringFactoriesLoader,它会从 META-INF/spring.factories 文件中加载所有需要自动配置的类。这种文件配置的方式让 Spring Boot 能够轻松拓展新的自动配置功能。

@EnableAutoConfiguration 通过 AutoConfigurationImportSelector 来加载自动配置类,自动配置的实现类和逻辑则由 @Conditional 注解管理,这样使得自动配置具有按需加载的特性。

2,条件注解与场景应用

自动配置机制在实际业务中应用非常广泛。举例来说,Spring Boot 中数据源的配置是通过 DataSourceAutoConfiguration 类实现的。在 DataSourceAutoConfiguration 中,使用 @ConditionalOnClass 注解来判断类路径中是否存在 DataSource 类,若存在,则注入数据源配置。

这类场景非常适合用在多数据源配置上,开发者可以利用条件注解在生产环境下配置多个数据库源,而在测试环境中只加载测试数据源配置。


五、嵌入式容器的启动流程

Spring Boot 在 Web 应用中默认使用嵌入式容器,这样可以使应用独立于外部服务器而运行,提升了应用的独立性和便捷性。

1,嵌入式容器的启动设计

在 Spring Boot 启动 Web 应用时,会根据 ServletWebServerApplicationContext 加载嵌入式容器。以下是启动嵌入式容器的关键流程:

  1. 创建 ServletWebServerApplicationContext:Spring Boot 会选择 Web 应用的上下文类 ServletWebServerApplicationContext,并加载 WebServerFactory 工厂类。
  2. 创建 Web 服务器:Spring Boot 使用工厂类创建内嵌的 Web 服务器,如 Tomcat、Jetty 或 Undertow。
  3. 注册 DispatcherServlet:Spring Boot 将 DispatcherServlet 注册到内嵌服务器中,并通过 ServletRegistrationBean 对其进行初始化和配置。

这种设计模式使得 Spring Boot 应用无缝支持不同类型的 Web 容器,并根据环境灵活选择合适的容器。

2,嵌入式容器在多环境中的应用

嵌入式容器尤其适合微服务架构,它能在容器化场景中快速适应 Docker 或 Kubernetes 等部署平台。此外,Spring Boot 允许开发者通过简单配置切换不同类型的 Web 服务器(如 Tomcat 到 Jetty),这样的设计为企业级应用提供了高灵活性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/829037.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024网鼎杯-初赛-青龙组

初赛-青龙组题目附件下载: https://pan.baidu.com/s/1VbieB2XhNYtRqfBeLxguYw?pwd=c03iMisc misc02 ​​生蚝:foremost分离,zsteg对最大的png,得到Y3p_Ke9_1s_????? 搜7z找到压缩包,然后掩码爆破,得到flag.txt,然后写脚本爆破。得到字符串我们先用 foremost 分离题…

闲话 11.8

杂项乱写 11.8别问为啥这么晚才写,因为一天都不知道在干啥,要寄的节奏。11.7 晚轮到 CTH 写字Ratio:程立雪?啥意思,程门立雪?门呢? CTH:让我创掉了。上午把昨天晚上想到的题出了出来,见此。 由于 5k 们要打 nfls,所以只能找团委了,过了 hack 之后直接拿 \(\mathcal{…

Hive的搭建

一、上传解压配置环境变量 1.解压 tar -zxvf apache-hive-3.1.2-bin.tar.gz -C ../2.配置环境变量 vim /etc/profile3、重命名 mv apache-hive-3.1.2-bin hive-3.1.24.使环境变量生效 source /etc/profile 二、修改配置文件 1.拷贝一份文件 cp hive-default.xml.template hive-…

自动泊车端到端算法 ParkingE2E 介绍

01 算法介绍 自主泊车是智能驾驶领域中的一项关键任务。传统的泊车算法通常使用基于规则的方案来实现。因为算法设计复杂,这些方法在复杂泊车场景中的有效性较低。 相比之下,基于神经网络的方法往往比基于规则的方法更加直观和多功能。通过收集大量专家泊车轨迹数据,基于学习…

hive基础知识分享(三)

今天学习hive的最后部分!写在前面 今天继续学习hive部分的知识。 Hive中如何实现行列转换一行变多行 可以对表使用 LATERAL VIEW EXPLODE(),也可以直接使用 EXPLAIN() 函数来处理一行数据。 SELECT name, col1 FROM testarray2 LATERAL VIEW EXPLODE(weight) t1 AS col1;多行…

一文读懂远程控制协议—Remote Control Protocol

RCP是一种轻量级的通信协议,核心理念是将边缘节点控制器中MCU的协议转换功能迁移至区域控制器ZCU甚至中央控制器Central ECU中实现,从而实现针对边缘节点的远程控制,实现网络中软件集中化,边缘节点轻量化。 随着中央计算+区域控制的中央集中式架构广泛应用,10BASE-T…

2024-2025-1 20241305 《计算机基础与程序设计》第七周学习总结

作业信息这个作业属于哪个课程 2024-2025-1-计算机基础与程序设计(https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP)这个作业要求在哪里 2024-2025-1计算机基础与程序设计第七周作业这个作业的目标 1、数组与链表2、基于数组和基于链表实现数据结构3、无序表与有序表4、…

OSSFileBrowse:OSS存储桶遍历漏洞利用工具

简介: 由于经常遇到存储桶遍历漏洞,直接访问文件是下载,不方便预览,且甲方要求证明该存储桶的危害,因此该工具应运而生。 使用javafx做图形化,kkFileView做文件预览接口。 使用: 命令行运行: java -Dfile.encoding=UTF-8 -jar OSSFileBrowse-1.0-SNAPSHOT.jar或者直接点…

NetExec:新型内网/域渗透工具

免责声明 仅供安全研究与学习之用,若将工具做其他用途,由使用者承担全部法律及连带责任,作者及发布者不承担任何法律及连带责任。简介: NetExec是一款强大的自动化网络安全评估和漏洞测试工具,作为已停止维护的CrackMapExec(CME)的现代替代品,它已被渗透测试人员和红队成…

2024-2025-1 20241407《计算机基础与程序设计》第七周学习总结

这个作业属于哪个课程 [2024-2025-1 计算机基础与程序设计](https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP)这个作业要求在哪里 2024-2025-1计算机基础与程序设计第七周作业这个作业的目标 学习数组与链表,基于数组和基于链表实现数据结构,无序表与有序表,树,图…

mysql ubuntu 卸载

mysql 卸载 :引用https://developer.aliyun.com/article/1306777 在 Ubuntu 系统中,MySQL 是一种常用的关系型数据库服务器。有时,我们可能需要完全卸载 MySQL 服务器,包括所有配置文件和数据,以便重新安装或切换到其他数据库服务器。本文将详细介绍在 Ubuntu 中如何完全卸…