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

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:

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) 引入了一个选择器,这个选择器做的事情是:

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

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 → 业务代码直接注入使用。

相关推荐
安易算力11 分钟前
智算中心网络架构选型:RDMA、InfiniBand与以太网技术深度对比及部署实践
网络·架构
用户7773979099319 分钟前
REA 逆向工程炸出 15W+ 热度,我却在想另一件事:当 AI 写的代码比你能读的还多,怎么办?
架构
Thneonl44 分钟前
Spark 比 MR 快在哪?管住最贵的 shuffle
后端·架构
海带紫菜菠萝汤1 小时前
本周 AI 观察:算力、路由、账本——护城河正搬出模型层
人工智能·ai·程序员·架构·大模型
隐擎fox2 小时前
解密 BGP Anycast 边缘路由与跨国链路质量检测:多租户网络出口的低时延与防丢包架构实战
网络·python·网络协议·tcp/ip·网络安全·架构·tcpdump
Shulex3 小时前
Shopify 独立站弃购挽回与客服实时转化:Shulex 实战架构指南
大数据·人工智能·架构·智能客服·跨境电商
March.s4 小时前
Redis 核心知识与高可用架构实践
数据库·redis·架构
mldong4 小时前
八种语言的工作流引擎,我用 6 张 UML 图画完了
后端·架构
数据库小学妹12 小时前
国产数据库怎么选?兼容、迁移、核心案例与融合架构四道关
数据库·架构·国产数据库·数据库迁移·融合数据库
霸道流氓气质13 小时前
Serverless 架构入门与实战:FaaS/BaaS 模型、Spring Cloud Function 适配与 AI 推理冷启动优化的 Java 全栈指南
spring cloud·架构·serverless