欢迎光临
我们一直在努力

SpringBoot 启动流程深度解析:源码追踪与事件监听机制

文章目录

  • Bean 依赖的属性配置管理
    • 属性类定义
    • 业务功能 Bean 定义
    • 配置文件示例
  • 自动配置原理详解
    • 自动配置的工作流程
    • 自动配置实战示例:短信服务
      • 定义核心功能类
      • 定义配置属性类
      • 创建自动配置类
      • 注册自动配置类
      • 使用自动配置
    • 工作流程总结
  • 自定义自动配置行为
    • 通过 YAML 配置排除
    • 通过注解参数排除
    • 通过排除坐标控制

Bean 依赖的属性配置管理

了解 Bean 依赖的属性配置管理是理解 SpringBoot 自动配置原理的前提。

属性类定义

将业务功能 Bean 运行所需的资源抽取为独立的属性类(xxxProperties)读取配置文件信息。以短信服务为例:

@Data
@ConfigurationProperties("sms")
public class SmsProperties {
/**
* 访问密钥
*/

private String accessKey = "default-access-key";

/**
* 密钥
*/

private String secretKey = "default-secret-key";

/**
* 短信签名
*/

private String signName = "默认签名";
}

注意:@ConfigurationProperties 类通常不需要 @Component 注解,而是通过 @EnableConfigurationProperties 来启用,这样可以更好地控制 Bean 的加载时机。

业务功能 Bean 定义

定义业务功能 Bean,通过 @EnableConfigurationProperties 启用属性类,并在构造函数中注入属性配置:

@Slf4j
@Component
@EnableConfigurationProperties(SmsProperties.class)
public class SimpleSmsClient {

private String accessKey;
private String secretKey;
private String signName;

public SimpleSmsClient(SmsProperties smsProperties) {
this.accessKey = smsProperties.getAccessKey();
this.secretKey = smsProperties.getSecretKey();
this.signName = smsProperties.getSignName();
log.info("短信客户端初始化完成,签名:{}", signName);
}

public void send(String phone, String content) {
log.info("发送短信 -> 手机号:{},内容:{},签名:{}", phone, content, signName);
// 实际发送短信的逻辑
}
}

配置文件示例

这样就简单的实现了 Bean 依赖的属性管理,解耦了 Bean 的强制加载,并通过设置默认值的方式解耦了属性的强制依赖。在 SpringBoot 配置文件 application.yml 中,可以定义属性 Bean 需要的属性来覆盖默认值:

sms:
access-key: youraccesskey
secret-key: yoursecretkey
sign-name: 我的应用

如果不配置这些属性,Bean 将使用 SmsProperties 中定义的默认值。这种方式实现了配置的灵活性,既可以使用默认配置快速启动,也可以根据实际需求自定义配置。

自动配置原理详解

自动配置是指 SpringBoot 根据开发者引入的依赖类,自动加载可能使用到的 Bean。其核心价值在于提升开发效率。自动配置可能需要配置相关参数,例如 MySQL 数据源的配置等。

自动配置的工作流程

自动配置的核心思想可以概括为:

  • 初始化环境:SpringBoot 初始化 Spring 容器的基础环境,读取用户的配置信息,加载用户自定义的 Bean 和引入的其他依赖坐标,形成初始化环境;

  • 加载技术集:SpringBoot 在启动时通过读取 classpath 下所有 jar 包中的配置文件来加载技术集 A 包含的所有自动配置类(此时加载的部分内容可能是无效或无作用的)。具体机制为:

    • Spring Boot 2.7 之前:读取 META-INF/spring.factories 文件中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 键对应的自动配置类列表
    • Spring Boot 2.7+:读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中声明的自动配置类列表
  • 条件匹配:SpringBoot 为技术集 A 中的每一个技术约定了启动该技术所对应的条件,并设置为按条件加载。由于开发者引入了一些 Bean 和其他依赖坐标,即形成了初始化环境,此时根据该初始化环境与 SpringBoot 的技术集 A 进行匹配,将满足条件的技术进行加载;

  • 默认配置:由于某些技术不进行配置就无法正常工作,因此 SpringBoot 引入了设置集 B。SpringBoot 统计了各个国家各个行业的开发者使用某个技术时最常用的配置,然后将这些配置作为默认值直接设置(SpringBoot 默认配置);

  • 配置覆盖:在不需要默认配置的情况下,可以通过 SpringBoot 开放的修改设置集 B 的接口对默认配置进行覆盖。

  • 自动配置实战示例:短信服务

    以短信服务为例,演示如何开发一个自动配置功能,让用户只需引入依赖并配置参数,就能直接使用短信发送功能。

    定义核心功能类

    首先定义短信服务类,这是实际提供业务功能的类,该技术隶属于上述的技术集 A:

    @Slf4j
    public class SmsService {

    private String accessKey;
    private String secretKey;
    private String signName;

    public SmsService(String accessKey, String secretKey, String signName) {
    this.accessKey = accessKey;
    this.secretKey = secretKey;
    this.signName = signName;
    log.info("短信服务初始化完成,签名:{}", signName);
    }

    /**
    * 发送短信
    */

    public boolean sendSms(String phone, String content) {
    log.info("发送短信 -> 手机号:{},内容:{},签名:{}", phone, content, signName);
    // 实际发送短信的逻辑(这里简化处理)
    return true;
    }
    }

    定义配置属性类

    定义一个属性类来封装短信服务的配置参数,该配置隶属于上述的设置集 B:

    @Data
    @ConfigurationProperties(prefix = "sms")
    public class SmsProperties {

    /**
    * 访问密钥
    */

    private String accessKey = "default-access-key";

    /**
    * 密钥
    */

    private String secretKey = "default-secret-key";

    /**
    * 短信签名
    */

    private String signName = "默认签名";

    /**
    * 是否启用短信服务
    */

    private boolean enabled = true;
    }

    创建自动配置类

    创建自动配置类,当满足条件时自动创建 SmsService Bean:

    @Configuration
    @EnableConfigurationProperties(SmsProperties.class)
    @ConditionalOnProperty(prefix = "sms", name = "enabled", havingValue = "true", matchIfMissing = true)
    public class SmsAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(SmsService.class)
    public SmsService smsService(SmsProperties properties) {
    return new SmsService(
    properties.getAccessKey(),
    properties.getSecretKey(),
    properties.getSignName()
    );
    }
    }

    关键注解说明:

    • @Configuration:标识这是一个配置类
    • @EnableConfigurationProperties:启用配置属性类,将 SmsProperties 注入到容器
    • @ConditionalOnProperty:条件装配,只有当 sms.enabled=true 时才加载(默认为 true)
    • @ConditionalOnMissingBean(SmsService.class):当容器中不存在 SmsService 时才创建,允许用户自定义覆盖

    注册自动配置类

    在 resources 目录下创建自动配置文件,让 SpringBoot 能够发现这个自动配置类:

    Spring Boot 2.7 之前的方式:创建 META-INF/spring.factories 文件

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
    com.example.sms.autoconfigure.SmsAutoConfiguration

    Spring Boot 2.7+ 推荐方式:创建 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件

    com.example.sms.autoconfigure.SmsAutoConfiguration

    使用自动配置

    在 application.yml 中配置参数:

    sms:
    enabled: true
    access-key: youraccesskey
    secret-key: yoursecretkey
    sign-name: 我的应用

    在业务代码中直接注入使用:

    @RestController
    public class UserController {

    @Autowired
    private SmsService smsService;

    @PostMapping("/sendCode")
    public String sendVerificationCode(String phone) {
    String code = "123456";
    smsService.sendSms(phone, "您的验证码是:" + code);
    return "发送成功";
    }
    }

    工作流程总结

  • SpringBoot 启动时扫描 classpath 下所有 jar 包中的自动配置文件:
    • Spring Boot 2.7 之前:扫描 META-INF/spring.factories 文件
    • Spring Boot 2.7+:扫描 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件
  • 发现 SmsAutoConfiguration 配置类
  • 检查 @ConditionalOnProperty 条件,判断 sms.enabled 是否为 true
  • 条件满足,加载 SmsProperties 配置属性类,读取 application.yml 中的配置
  • 检查 @ConditionalOnMissingBean 条件,容器中不存在 SmsService
  • 创建 SmsService Bean,注入配置参数
  • 用户可以直接通过 @Autowired 使用 SmsService
  • 这样,用户只需引入依赖、添加配置,就能自动获得短信发送功能,无需手动创建 Bean,体现了 SpringBoot “约定优于配置” 的设计理念。

    自定义自动配置行为

    SpringBoot 的自动配置并非强制执行,可以通过配置的形式干预是否启用对应的自动配置功能。

    对于自动配置的执行过程,可以根据自动配置流程进行一些高级定制。例如系统默认会加载 100 多种自动配置的技术,可以手动干预此工程,禁用自动配置。

    通过 YAML 配置排除

    通过 YAML 配置设置排除指定的自动配置类:

    spring:
    autoconfigure:
    exclude:
    org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration

    通过注解参数排除

    通过注解参数排除自动配置类:

    // 在启动类或配置类上使用,排除指定的自动配置类
    @SpringBootApplication
    @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }

    // 或者使用 excludeName 通过类名字符串排除
    @EnableAutoConfiguration(excludeName = "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration")

    通过排除坐标控制

    如果当前自动配置中包含有更多的自动配置功能,也就是一个套娃的效果。此时可以通过检测条件的控制来管理自动配置是否启动。

    例如 web 程序启动时会自动启动 tomcat 服务器,可以通过排除坐标的方式,让加载 tomcat 服务器的条件失效。不过需要提醒一点,你把 tomcat 排除掉,记得再加一种可以运行的服务器。

    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!–web起步依赖环境中,排除Tomcat起步依赖,匹配自动配置条件–>
    <exclusions>
    <exclusion>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    <!–添加Jetty起步依赖,匹配自动配置条件–>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
    </dependencies>

    赞(0)
    未经允许不得转载:171主机测评 » SpringBoot 启动流程深度解析:源码追踪与事件监听机制
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址