SpringBoot核心原理:自动配置、starter、SPI机制
SpringBoot就像一个贴心管家,你想要什么它提前帮你摆好,不用你操心配置。但管家是怎么知道你想要什么的?这篇就拆开它的脑袋看看。
一、SpringBoot vs 传统Spring
传统Spring项目有多折磨人?一堆XML配置文件,配个数据源能写半屏XML,漏个分号项目就启动不了。
SpringBoot的三个核心改变:
- 约定大于配置: sensible defaults,你不配就用默认值
- 内嵌Tomcat :不需要单独部署war包,
java -jar直接跑 - 零XML配置:用注解和Java配置类替代XML
一句话总结:SpringBoot不是新框架,它是Spring的"全家桶套餐+自动安装服务"。
二、起步依赖(starter)原理
2.1 starter是什么
starter是SpringBoot提供的一组依赖打包方案 。比如你引入 spring-boot-starter-web:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
一个依赖进来,背后实际上带了一大堆东西:
| 包含的依赖 | 作用 |
|---|---|
| spring-web | Spring MVC核心 |
| spring-webmvc | MVC框架 |
| tomcat-embed-core | 内嵌Tomcat |
| jackson-databind | JSON序列化 |
| 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 是个复合注解,拆开看:
java
@SpringBootConfiguration // 本质是@Configuration,标记配置类
@EnableAutoConfiguration // 自动配置的开关
@ComponentScan // 组件扫描,扫描当前包及子包
public class MyApplication { ... }
核心是 @EnableAutoConfiguration。
3.2 从注解到AutoConfiguration.imports
@EnableAutoConfiguration 通过 @Import(AutoConfigurationImportSelector.class) 引入了一个选择器,这个选择器做的事情是:
- 读取
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件 - 把里面列出的所有自动配置类加载进来
SpringBoot 3.x之前用的是 META-INF/spring.factories,3.x之后改成了 AutoConfiguration.imports 文件,目的更清晰------把自动配置类和普通SPI配置分开。
文件内容长这样:
python
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
... (几百个)
3.3 条件装配注解
光加载配置类还不够,如果项目里没引Redis依赖,RedisAutoConfiguration加载了也白搭。所以每个配置类上都有一堆条件注解:
| 注解 | 条件 |
|---|---|
@ConditionalOnClass |
classpath存在指定类时才生效 |
@ConditionalOnBean |
容器中存在指定Bean时才生效 |
@ConditionalOnProperty |
配置文件中存在指定属性时才生效 |
@ConditionalOnMissingBean |
容器中不存在指定Bean时才生效(让你能覆盖默认配置) |
@ConditionalOnWebApplication |
是Web应用时才生效 |
举例:
java
@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
// 只有classpath有Redis相关类,这个配置类才会生效
}
3.4 自动配置执行流程
scss
启动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 SPI | SpringBoot SPI |
|---|---|---|
| 配置文件位置 | META-INF/services/ | META-INF/spring/ |
| 配置文件名 | 接口全限定名 | AutoConfiguration.imports |
| 加载机制 | ServiceLoader | AutoConfigurationImportSelector |
| 是否支持条件过滤 | 否,全部加载 | 是,通过@Conditional |
Java SPI的缺点是"一刀切全加载",SpringBoot在此基础上加了条件判断,只加载需要的,这就是进步。
五、实战:自定义一个starter
光说不练假把式,我们来手写一个简单的starter。
5.1 项目结构
bash
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 核心代码
配置属性类:
java
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
private String name = "World";
private int times = 1;
// getter/setter省略
}
服务类:
java
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省略
}
自动配置类:
java
@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后,直接注入就能用:
java
@RestController
public class TestController {
@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String hello() {
return helloService.sayHello();
}
}
在 application.yml 中配置参数:
yaml
hello:
name: 黑漂技术佬
times: 3
启动项目访问 /hello,就能看到效果了。
这就是SpringBoot自动配置的完整闭环:starter声明依赖 → AutoConfiguration.imports注册配置类 → @Conditional条件判断 → @EnableConfigurationProperties绑定参数 → 注册Bean → 业务代码直接注入使用。