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

相关推荐
天空属于哈夫克34 天前
企业微信二次开发:精准实现关键词自动回复
架构·企业微信
晨米酱4 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
这个DBA有点耶4 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
码流子4 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
moMo4 天前
从固定流程到问题路由:让 LangGraph RAG 按需检索
架构
白远山4 天前
上海24小时自助健身房解决方案实战指南与经验分享
java·数据库·架构·需求分析
LorryJovens4 天前
【LAAP科研】双系统具身AGI范式研究——基于LAAP认知架构与Jev概率决策模型的系统性技术调研与范式验证
人工智能·gpt·安全·架构
JQweryuiop5 天前
中小型游戏陪练工作室数字化管理实践:基于七彩屋电竞护航小程序订单、履约与绩效系统的落地复盘
大数据·游戏·小程序·架构
LONGZETECH5 天前
一线职教实测:风光 580 汽车故障诊断仿真系统,破解实车实训四大核心痛点
人工智能·学习·安全·架构·汽车
萧瑟余晖5 天前
Netty 核心组件与 Reactor 模型详解
网络·架构