不再困惑:Spring Boot Starter 的原理与自定义实战
- 前言
- 一、Starter 是什么?
- 二、Starter 的命名规范
- 三、一个 Starter 由哪几部分组成?
- 四、Starter 自动配置的核心流程
- 五、手写一个 Starter:实战环节
- 步骤 1:创建 Maven 多模块项目
- 步骤 2:编写配置属性类
- 步骤 3:编写核心服务类
- 步骤 4:编写自动配置类
- 步骤 5:注册自动配置类(关键一步)
- 步骤 6:在 starter 模块中依赖 autoconfigure
- 步骤 7:使用
- 六、常见的条件注解汇总
- 七、Starter 与普通依赖的区别
- 八、常见面试题
- Q1:`@ConditionalOnMissingBean` 有什么作用?
- Q2:Starter 中的配置属性是怎么绑定的?
- Q3:多个 Starter 之间有依赖关系怎么办?
- Q4:如何排除某个自动配置类?
- 九、核心总结
🌺The Begin🌺点点关注,收藏不迷路🌺 ⬇ ⬇ 底部 ⬇ ⬇ |
前言
初学 Spring Boot 时,我们总会被一个概念反复“洗脑”:
只要引入一个
starter,就能自动拥有某个功能,比如 Web、Redis、MyBatis……
但你有没有想过:
- Starter 到底是什么?
- 它凭什么能做到“引入即用”?
- 如何自己写一个 Starter 给别人用?
今天这篇文章,我们从定义 → 组成 → 原理 → 自定义实战,彻底讲透 Spring Boot Starter。
一、Starter 是什么?
官方定义:
Starters are a set of convenient dependency descriptors that you can include in your application.
翻译过来:Starter 是一组“方便依赖描述符”。
用人话说:
- Starter 是一个Maven/Gradle 依赖
- 它把某个功能所需的所有依赖 + 自动配置打包在一起
- 你只需引入一个坐标,不用手动配版本、不用写配置类
举个例子:
传统 SSM 整合 Redis 需要:
- 引入
jedis+spring-data-redis+ 连接池 - 手动配置
JedisConnectionFactory - 手动配置
RedisTemplate
而用 Spring Boot Starter:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>搞定!RedisTemplate已经自动注入好了。
二、Starter 的命名规范
| 类型 | 命名格式 | 示例 |
|---|---|---|
| 官方 starter | spring-boot-starter-* | spring-boot-starter-web |
| 第三方 starter | *-spring-boot-starter | mybatis-spring-boot-starter |
为什么要区分?Spring Boot 在扫描自动配置时会优先处理官方命名,但实际功能没区别。
三、一个 Starter 由哪几部分组成?
一个完整的 Starter 通常包含两个模块:
┌─────────────────────────────────────────────┐ │ xxx-spring-boot-starter │ ← 空壳模块 │ - 不写任何代码 │ │ - 只依赖 auto-configuration 模块 │ └─────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────┐ │ xxx-spring-boot-autoconfigure │ ← 核心模块 │ - 自动配置类 (@Configuration) │ │ - 配置属性类 (@ConfigurationProperties) │ │ - META-INF/spring/...AutoConfiguration.imports │ └─────────────────────────────────────────────┘为什么分两个模块?
- starter:给最终用户引入的,只做依赖聚合
- autoconfigure:存放自动配置逻辑,独立测试更干净
也可以只用一个模块,但不推荐。
四、Starter 自动配置的核心流程
应用启动 │ ▼ @SpringBootApplication │ ▼ @EnableAutoConfiguration │ ▼ AutoConfigurationImportSelector │ ▼ 扫描 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports │ ▼ 加载所有自动配置类 (如 RedisAutoConfiguration) │ ▼ @Conditional 系列注解按条件生效 │ ▼ 创建并注册 Bean五、手写一个 Starter:实战环节
假设我们要做一个敏感词过滤 Starter,引入后自动注入SensitiveWordFilter。
步骤 1:创建 Maven 多模块项目
demo-starter-parent/ ├── sensitiveword-spring-boot-starter/ (空壳) └── sensitiveword-spring-boot-autoconfigure/ (核心)步骤 2:编写配置属性类
// 在 autoconfigure 模块中@ConfigurationProperties(prefix="sensitive.word")publicclassSensitiveWordProperties{/** * 是否启用敏感词过滤 */privatebooleanenabled=true;/** * 敏感词列表 */privateList<String>words=newArrayList<>();// getter / setter 省略}步骤 3:编写核心服务类
publicclassSensitiveWordFilter{privatefinalSensitiveWordPropertiesproperties;publicSensitiveWordFilter(SensitiveWordPropertiesproperties){this.properties=properties;}publicStringfilter(Stringtext){if(!properties.isEnabled()){returntext;}Stringresult=text;for(Stringword:properties.getWords()){result=result.replace(word,"***");}returnresult;}}步骤 4:编写自动配置类
@Configuration@ConditionalOnClass(SensitiveWordFilter.class)@EnableConfigurationProperties(SensitiveWordProperties.class)publicclassSensitiveWordAutoConfiguration{@Bean@ConditionalOnMissingBean@ConditionalOnProperty(prefix="sensitive.word",name="enabled",havingValue="true",matchIfMissing=true)publicSensitiveWordFiltersensitiveWordFilter(SensitiveWordPropertiesproperties){returnnewSensitiveWordFilter(properties);}}步骤 5:注册自动配置类(关键一步)
在autoconfigure模块的resources/META-INF/spring/下创建文件:
文件路径:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件内容: com.example.sensitiveword.autoconfigure.SensitiveWordAutoConfiguration⚠️ Spring Boot 2.7+ 用
AutoConfiguration.imports
旧版用spring.factories
步骤 6:在 starter 模块中依赖 autoconfigure
<!-- sensitiveword-spring-boot-starter/pom.xml --><dependencies><dependency><groupId>com.example</groupId><artifactId>sensitiveword-spring-boot-autoconfigure</artifactId></dependency></dependencies>步骤 7:使用
在其他项目中引入:
<dependency><groupId>com.example</groupId><artifactId>sensitiveword-spring-boot-starter</artifactId><version>1.0.0</version></dependency>配置application.yml:
sensitive:word:enabled:truewords:-笨蛋-垃圾自动注入使用:
@AutowiredprivateSensitiveWordFilterfilter;filter.filter("你这个笨蛋");// 输出:你这个***六、常见的条件注解汇总
编写 Starter 时最常用的注解:
| 注解 | 作用 |
|---|---|
@ConditionalOnClass | 类路径存在某类才生效 |
@ConditionalOnMissingClass | 类路径不存在某类才生效 |
@ConditionalOnBean | 容器中存在某 Bean 才生效 |
@ConditionalOnMissingBean | 容器中不存在某 Bean 才生效 |
@ConditionalOnProperty | 配置文件中存在某属性且值匹配才生效 |
@ConditionalOnWebApplication | 当前是 Web 环境才生效 |
@ConditionalOnNotWebApplication | 当前不是 Web 环境才生效 |
@ConditionalOnExpression | SpEL 表达式为 true 才生效 |
使用示例:
@Bean@ConditionalOnProperty(prefix="cache",name="type",havingValue="redis")publicCacheServiceredisCacheService(){returnnewRedisCacheService();}七、Starter 与普通依赖的区别
| 对比维度 | 普通依赖 | Starter |
|---|---|---|
| 内容 | 只是一堆 jar 包 | 依赖 + 自动配置逻辑 |
| 配置 | 需要手动写@Bean或 XML | 自动注入 |
| 版本管理 | 容易冲突 | 内置版本(BOM) |
| 开箱即用 | ❌ | ✅ |
八、常见面试题
Q1:@ConditionalOnMissingBean有什么作用?
保证用户可以通过自己定义 Bean来覆盖 Starter 的默认实现。这是 Starter 可被扩展的关键。
Q2:Starter 中的配置属性是怎么绑定的?
通过@ConfigurationProperties+@EnableConfigurationProperties。Spring Boot 会自动把application.yml中prefix对应的配置映射到 Java 属性对象。
Q3:多个 Starter 之间有依赖关系怎么办?
在pom.xml中正常引入即可。Spring Boot 会合并加载所有自动配置类,通过@AutoConfigureBefore/@AutoConfigureAfter/@AutoConfigureOrder控制加载顺序。
@AutoConfigureAfter(DataSourceAutoConfiguration.class)publicclassMyBatisAutoConfiguration{// ...}Q4:如何排除某个自动配置类?
spring:autoconfigure:exclude:-org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration或通过注解:
@EnableAutoConfiguration(exclude=DataSourceAutoConfiguration.class)九、核心总结
| 问题 | 答案 |
|---|---|
| Starter 是什么? | 一个“聚合依赖 + 自动配置”的 Maven 依赖 |
| 为什么能自动配置? | @EnableAutoConfiguration+ 扫描AutoConfiguration.imports |
| 如何控制按需加载? | @Conditional系列注解 |
| 如何让用户覆盖默认 Bean? | @ConditionalOnMissingBean |
| 如何绑定配置文件? | @ConfigurationProperties |
最终一句话理解 Starter:
Starter = 一组依赖 + 一个被条件注解约束的自动配置类 + 一个注册入口(
AutoConfiguration.imports)
搞懂了这个,你不仅能熟练使用各种 Starter,还能写出自己的企业级 Starter,甚至能看懂 Spring Boot 的大量源码。
🌺The End🌺点点关注,收藏不迷路🌺 ⬆ ⬆ 顶部 ⬆ ⬆ |