SpringBoot核心原理:自动配置、starter、SPI机制

99 阅读4分钟

SpringBoot核心原理:自动配置、starter、SPI机制

SpringBoot就像一个贴心管家,你想要什么它提前帮你摆好,不用你操心配置。但管家是怎么知道你想要什么的?这篇就拆开它的脑袋看看。

一、SpringBoot vs 传统Spring

传统Spring项目有多折磨人?一堆XML配置文件,配个数据源能写半屏XML,漏个分号项目就启动不了。

SpringBoot的三个核心改变:

  1. 约定大于配置: sensible defaults,你不配就用默认值
  2. 内嵌Tomcat:不需要单独部署war包,java -jar 直接跑
  3. 零XML配置:用注解和Java配置类替代XML

一句话总结:SpringBoot不是新框架,它是Spring的"全家桶套餐+自动安装服务"。

二、起步依赖(starter)原理

2.1 starter是什么

starter是SpringBoot提供的一组依赖打包方案。比如你引入 spring-boot-starter-web:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

一个依赖进来,背后实际上带了一大堆东西:

包含的依赖作用
spring-webSpring MVC核心
spring-webmvcMVC框架
tomcat-embed-core内嵌Tomcat
jackson-databindJSON序列化
spring-boot-starter-validation参数校验

2.2 依赖传递机制

Maven的依赖传递(transitive dependency)是starter能工作的底层机制。A依赖B,B依赖C,A自动获得C。所以你只写一行 <dependency>,Maven帮你把整棵依赖树拉进来。

这就是为什么SpringBoot项目的pom.xml看起来特别干净——复杂度被starter封装掉了。

三、自动配置核心原理

这是SpringBoot的灵魂所在。

3.1 @SpringBootApplication注解拆解

启动类上的 @SpringBootApplication 是个复合注解,拆开看:

@SpringBootConfiguration   // 本质是@Configuration,标记配置类
@EnableAutoConfiguration   // 自动配置的开关
@ComponentScan             // 组件扫描,扫描当前包及子包
public class MyApplication { ... }

核心是 @EnableAutoConfiguration。

3.2 从注解到AutoConfiguration.imports

@EnableAutoConfiguration 通过 @Import(AutoConfigurationImportSelector.class) 引入了一个选择器,这个选择器做的事情是:

  1. 读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件
  2. 把里面列出的所有自动配置类加载进来

SpringBoot 3.x之前用的是 META-INF/spring.factories,3.x之后改成了 AutoConfiguration.imports 文件,目的更清晰——把自动配置类和普通SPI配置分开。

文件内容长这样:

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
... (几百个)

3.3 条件装配注解

光加载配置类还不够,如果项目里没引Redis依赖,RedisAutoConfiguration加载了也白搭。所以每个配置类上都有一堆条件注解:

注解条件
@ConditionalOnClassclasspath存在指定类时才生效
@ConditionalOnBean容器中存在指定Bean时才生效
@ConditionalOnProperty配置文件中存在指定属性时才生效
@ConditionalOnMissingBean容器中不存在指定Bean时才生效(让你能覆盖默认配置)
@ConditionalOnWebApplication是Web应用时才生效

举例:

@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
    // 只有classpath有Redis相关类,这个配置类才会生效
}

3.4 自动配置执行流程

启动main方法
  → 创建SpringApplication
    → refreshContext() 刷新容器
      → invokeBeanFactoryPostProcessors()
        → AutoConfigurationImportSelector执行
          → 读取AutoConfiguration.imports
            → 加载所有自动配置类
              → 逐个进行@Conditional条件判断
                → 条件满足 → 注册Bean到容器
                → 条件不满足 → 跳过

四、SPI机制简介

4.1 什么是SPI

SPI(Service Provider Interface)是一种服务发现机制。核心思想:定义接口在API包中,实现在各个SPI包中,运行时动态发现并加载实现。

4.2 Java SPI vs SpringBoot SPI

对比项Java SPISpringBoot SPI
配置文件位置META-INF/services/META-INF/spring/
配置文件名接口全限定名AutoConfiguration.imports
加载机制ServiceLoaderAutoConfigurationImportSelector
是否支持条件过滤否,全部加载是,通过@Conditional

Java SPI的缺点是"一刀切全加载",SpringBoot在此基础上加了条件判断,只加载需要的,这就是进步。

五、实战:自定义一个starter

光说不练假把式,我们来手写一个简单的starter。

5.1 项目结构

hello-spring-boot-starter/          # starter模块(空jar,只做依赖声明)
└── pom.xml

hello-spring-boot-autoconfigure/    # 自动配置模块
├── src/main/java/com/example/hello/
│   ├── HelloProperties.java        # 配置属性绑定类
│   ├── HelloService.java           # 核心服务类
│   └── HelloAutoConfiguration.java # 自动配置类
└── src/main/resources/
    └── META-INF/spring/
        └── org.springframework.boot.autoconfigure.AutoConfiguration.imports

5.2 核心代码

配置属性类:

@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
    private String name = "World";
    private int times = 1;
    // getter/setter省略
}

服务类:

public class HelloService {
    private HelloProperties properties;

    public String sayHello() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < properties.getTimes(); i++) {
            sb.append("Hello, ").append(properties.getName()).append("!\n");
        }
        return sb.toString();
    }
    // setter省略
}

自动配置类:

@AutoConfiguration
@ConditionalOnProperty(prefix = "hello", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public HelloService helloService(HelloProperties properties) {
        HelloService service = new HelloService();
        service.setProperties(properties);
        return service;
    }
}

AutoConfiguration.imports文件内容:

com.example.hello.HelloAutoConfiguration

5.3 使用方式

别的项目引入这个starter后,直接注入就能用:

@RestController
public class TestController {
    @Autowired
    private HelloService helloService;

    @GetMapping("/hello")
    public String hello() {
        return helloService.sayHello();
    }
}

在 application.yml 中配置参数:

hello:
  name: 黑漂技术佬
  times: 3

启动项目访问 /hello,就能看到效果了。

这就是SpringBoot自动配置的完整闭环:starter声明依赖 → AutoConfiguration.imports注册配置类 → @Conditional条件判断 → @EnableConfigurationProperties绑定参数 → 注册Bean → 业务代码直接注入使用。