java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot启动过程与自动配置

SpringBoot启动过程与自动配置过程解读

作者:没事学AI

本文详解SpringBoot启动流程及自动配置机制,涵盖main方法初始化、环境配置、容器启动等关键步骤,解析条件注解与spring.factories的智能配置逻辑,并提供自定义配置方法,强调其"约定优于配置"的核心理念与工程化封装特性

一、Spring Boot 启动流程

Spring Boot 应用的入口是 main 方法中的 SpringApplication.run(),但这行代码背后藏着一整套“初始化-配置-启动”的流水线。

我们可以将其分为构造阶段运行阶段两大步,每一步都有明确的职责边界。

1.1 构造阶段:初始化核心组件

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 = WebApplicationType.deduceFromClasspath();
    this.setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class));
    this.setListeners(getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}

1.2 运行阶段:从环境准备到容器启动

SpringApplication.run() 方法是真正的“执行引擎”,可细分为 10 个关键步骤,环环相扣:

  1. 启动监控与监听器:通过 StopWatch 记录启动时间,同时触发 SpringApplicationRunListeners.starting(),通知所有监听器“应用开始启动”。
  2. 环境配置:创建 ConfigurableEnvironment(根据应用类型选择 StandardServletEnvironmentStandardReactiveWebEnvironment),并加载系统变量、配置文件(如 application.yml)等。完成后调用 environmentPrepared 事件,允许监听器对环境进行二次调整。
  3. 打印 Banner:默认打印 Spring Boot 版本信息,可通过 resources/banner.txt 自定义(支持 ASCII 艺术或变量替换)。
  4. 创建应用上下文:根据应用类型生成对应的 IOC 容器,例如 Servlet 应用使用 AnnotationConfigServletWebServerApplicationContext
  5. 上下文准备:将环境、命令行参数等注入上下文,执行初始化器的 initialize 方法,并触发 contextPrepared 事件。
  6. 上下文刷新:调用 refreshContext,触发 Spring 容器的核心流程(Bean 定义加载、实例化、依赖注入等),同时启动嵌入式服务器(如 Tomcat)。
  7. 收尾工作:执行 afterRefresh(预留扩展点),停止计时器,并触发 started 事件。
  8. 回调自定义逻辑:从容器中获取 ApplicationRunnerCommandLineRunner 的实现类,按顺序执行其 run 方法(适合启动后初始化数据等操作)。
  9. 启动完成:触发 running 事件,应用正式就绪。
  10. 异常处理:若启动失败,调用 failed 事件,打印异常并关闭上下文。

实战技巧:若需在启动后执行初始化逻辑(如加载缓存),优先使用 ApplicationRunner(支持 ApplicationArguments 解析)而非 CommandLineRunner(直接接收字符串数组)。

二、自动配置:Spring Boot 的“智能配置”核心

Spring Boot 最令人称道的“自动配置”,本质是“基于条件的约定配置”。

它通过一套规则判断环境中存在的依赖,自动装配对应的组件,避免手动编写 XML 或 @Bean 配置。

2.1 自动配置的底层原理

自动配置的触发点是 @EnableAutoConfiguration 注解(被 @SpringBootApplication 间接包含),其核心逻辑在 AutoConfigurationImportSelector 中:

  1. 加载候选配置类:通过 SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader),扫描所有 Jar 包的 META-INF/spring.factories,获取 EnableAutoConfiguration 对应的配置类列表(如 HttpEncodingAutoConfigurationDataSourceAutoConfiguration 等)。
  2. 过滤与去重:移除重复或被排除的配置类(通过 @SpringBootApplication(exclude = ...) 指定),再通过条件注解(如 @ConditionalOnClass)判断配置类是否生效。
  3. 注入容器:将生效的配置类加载到容器中,其内部的 @Bean 方法会自动生成组件。

关键源码片段

// AutoConfigurationImportSelector 中加载候选配置类的逻辑
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories");
    return configurations;
}

2.2 条件注解:自动配置的“开关”

自动配置的“智能”依赖于 @Conditional 系列注解,它们决定了一个配置类或 @Bean 方法是否生效。

常用条件注解如下:

注解作用示例场景
@ConditionalOnClass类路径存在指定类时生效检测到 DataSource.class 时配置数据源
@ConditionalOnMissingBean容器中不存在指定 Bean 时生效若用户未定义 RestTemplate,则自动配置默认实例
@ConditionalOnProperty配置项满足条件时生效通过 spring.datasource.enabled=true 控制数据源是否启用
@ConditionalOnWebApplication仅 Web 应用生效配置 DispatcherServlet

实战案例:

HttpEncodingAutoConfiguration(HTTP 编码自动配置)的条件判断:

@Configuration
@EnableConfigurationProperties(HttpProperties.class) // 绑定配置文件属性
@ConditionalOnWebApplication(type = Type.SERVLET) // 仅 Servlet 应用生效
@ConditionalOnClass(CharacterEncodingFilter.class) // 存在字符编码过滤器类时生效
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean // 若用户未定义,则自动配置
    public CharacterEncodingFilter characterEncodingFilter() {
        // 从 HttpProperties 中读取配置(如 spring.http.encoding.charset=utf-8)
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(properties.getCharset().name());
        return filter;
    }
}

技巧

若需禁用某个自动配置(如默认的数据源配置),可通过

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 

或配置

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

2.3 自定义自动配置:扩展 Spring Boot

若需为自己的组件实现自动配置(如公司内部 SDK),需遵循以下步骤:

编写配置类:使用 @Configuration 和条件注解定义组件装配逻辑,通过 @EnableConfigurationProperties 绑定配置属性。

注册配置类:在 Jar 包的 META-INF/spring.factories 中添加:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.sdk.MyComponentAutoConfiguration

添加配置元数据:在 META-INF/spring-configuration-metadata.json 中定义配置项的描述(IDE 会自动提示),例如:

{
  "properties": [
    {
      "name": "example.sdk.enabled",
      "type": "java.lang.Boolean",
      "defaultValue": true,
      "description": "是否启用 SDK 组件"
    }
  ]
}

验证方法:启动应用时添加 --debug 参数,控制台会打印自动配置报告,显示哪些配置类生效(Positive matches)或不生效(Negative matches)。

三、总结:Spring Boot 便捷性的本质

Spring Boot 的启动流程和自动配置,本质是“约定优于配置”的极致体现:

理解这些原理后,不仅能更高效地排查问题(如启动慢、自动配置失效),还能灵活扩展 Spring Boot(如自定义 starters 或启动流程)。

记住:Spring Boot 不是“魔法”,而是对 Spring 框架的“工程化封装”——看透其源码,就能真正掌控它。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文