☰
Spring Boot 3.x起步依赖机制全解析:自动配置与版本管理
2026/10/4 23:18:31 网站建设 项目流程

1. 前言:这个依赖到底解决了什么问题

三年前我第一次用 Spring Boot 时,最让我震惊的不是“内嵌Tomcat”,也不是“约定优于配置”,而是**起步依赖(Starter)**这个东西。当时我在维护一个老项目,pom.xml 里躺着将近四十个依赖坐标,其中有一半是为了“把一个 Web 服务跑起来”而凑出来的,比如 spring-webmvc、jackson-databind、hibernate-validator、spring-boot-starter-tomcat 之类——每加一个新模块,你都得自己手工去对齐版本号,minio 的客户端拉进来一测,发现它默认带的 okhttp 版本和项目里另一个库冲突,光排除依赖就花了半天。

后来切到 Spring Boot 3.x,引入一个 spring-boot-starter-web,其他全自动搞定。同一个工程,pom 从四十多个坐标瘦身到十几个,启动项目配一次就通。这个体验差距,就是“起步依赖”设计价值的直观体现。

这篇文章我想把 Spring Boot 3.x 的起步依赖机制完整拆一遍,重点回答几个问题:Starter 到底是什么?它的自动配置原理是什么?为什么引入一个依赖就够了,而不会出现“一堆 jar 不知道干嘛”的失控局面?顺带会给出一个实际项目从零搭建的完整过程,以及我这些年踩过的版本冲突、自动配置失效之类的坑。

适合谁看:刚学 Spring Boot 3.x 的新人,能帮你把“引入依赖”这件事的底层逻辑吃透;已经写了几年项目但一直没空研究 Starter 原理的老开发,这篇也能帮你把知识体系补完整。

2. Starter 到底是什么:从命名规范到自动配置

2.1 命名里的学问:官方 Starter 与第三方 Starter

Spring Boot 的起步依赖,本质上就是一个普通 Maven 依赖坐标,但它不是孤立的,它会通过 Maven 的传递依赖(transitive dependency)机制,把你需要的全部 jar 一次性带进来,同时配套一个自动配置类,让你引入依赖之后,框架自动帮你把组件创建好、参数配好。你做的只有一件事:把坐标写进构建文件。

这里有一个非常值得注意的细节,是命名的约定。官方规范是这样的:spring-boot-starter-*这样的命名,代表这是 Spring 官方维护的起步依赖,比如spring-boot-starter-web、spring-boot-starter-data-redis。而第三方的起步依赖通常在中间带上自己的技术名,比如 MyBatis 的mybatis-spring-boot-starter,或者当当网 ShardingSphere 的sharding-jdbc-spring-boot-starter。

换句话说,只要看到*-spring-boot-starter这个模式,你就知道这是一个为 Spring Boot 自动配置专门设计的集成库。这不是一个硬性要求,但是社区事实上形成的一个默契。识别这个命名的意义在于:你在选型时,一眼就能判断哪些库是原生支持 Spring Boot 的,哪些库需要你自己写一堆@Configuration把它桥接进来。

2.2 为什么官方文档把 Starter 称为“一站式依赖解决方案”

我一直觉得,要理解 Starter,关键是先理解“传递依赖”和“自动配置”这两件事是怎么配合的。

先看传递依赖。一个spring-boot-starter-data-redis,光是它直接声明的传递依赖就包含 spring-data-redis、jedis 或 lettuce(Spring Boot 3.x 默认是 lettuce-core)、commons-pool2 等,这些依赖坐标的版本,全部由 Spring Boot 的依赖管理 BOM(Bill of Materials,物料清单)统一锁定。也就是说,你引入一个坐标,得到的不只是这一个 jar,而是一整套经过版本互测的 jar 组合。这个“经过互测”非常关键,因为 Spring Boot 并不是把你需要的 jar 随便堆在一起,它是在自己版本发布之前就把这些组件的兼容性跑过一遍的。

再看自动配置。每个官方(或规范化的第三方)Starter,它的 jar 包META-INF目录下都会有一个名为org.springframework.boot.autoconfigure.AutoConfiguration.imports的文件(如果是在 Spring Boot 2.x,是spring.factories文件),文件里罗列了若干个自动配置类的全限定名。当你启动 Spring Boot 应用时,@EnableAutoConfiguration注解会触发一个加载流程——它扫描所有 jar 里的这个 imports 文件,把这些自动配置类全部装载进 Spring 容器。

注意,这里有一个聪明之处:装载不代表生效。自动配置类内部几乎都有@ConditionalOnClass、@ConditionalOnMissingBean等条件注解,只有满足条件才会真正创建 Bean。比如,你引入了spring-boot-starter-web,类里检测到Servlet、DispatcherServlet这些类存在,才去自动创建DispatcherServlet、HandlerMapping等一整套 Web MVC 核心组件。同样,如果项目里既有 starter-data-redis,又有你手工定义的一个RedisTemplateBean,那么条件注解@ConditionalOnMissingBean就会失效,自动配置的RedisTemplate不会创建,你自定义的 Bean 会优先生效。

这样一套机制跑下来,最终的效果就是:引入依赖,就自动拥有了一个配置好的组件,不需要写@Configuration,不需要自己声明 Bean。你只需要在application.yml写几个属性键,比如spring.datasource.url,配置文件就会把值读出来填充到自动创建的组件里。

提示:Spring Boot 3.x 基于 Spring Framework 6,它的自动配置加载机制已经从spring.factories迁移到了AutoConfiguration.imports。如果你把 Spring Boot 2.x 的老笔记复制到 3.x 项目里,发现自定义自动配置类不生效,大概率就是文件路径不对。这个细节值得记下来。

3. 为什么一个依赖就够了:单点依赖背后的连锁反应

3.1 Maven 传递依赖:一个坐标带出三十个 jar

我在开头提到过一个只有最简单 Web 功能的项目。如果不用 Starter,你得手动写这样的 POM:

<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.1.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.17.0</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>10.1.19</version> </dependency> <!-- 还要 hibernate-validator、spring-aop、spring-expression、jakarta.servlet-api ... 一共要十几个 --> </dependencies>

且不说版本号你得一个一个去查,即使查到了,Spring 6.1 搭配 Jackson 2.16 大概率没问题,但搭配 Tomcat 10.0 还是 10.1?哪两个版本的组合在本地测试才不炸?这些都是靠社区版本兼容矩阵解决的,不是你一个人现查能查明白的。我见过太多同事把时间浪费在这件事上。

现在用官方有 Web 起步依赖,POM 是这样的:

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

没有写<version>,因为 Spring Boot 父 POM 或 BOM 已经把版本锁好了。我在实际项目里用mvn dependency:tree打过一次,spring-boot-starter-web这一个坐标,最终解析出来的 jar 数量是 31 个,其中就包含 spring-webmvc、jackson-databind、tomcat-embed-core、hibernate-validator、spring-web、spring-beans、spring-core 等所有你手写要写半天的东西。

“一个依赖”在 Maven 层面的实现原理,就是传递依赖。Maven 会把该坐标的 POM 里声明的所有<dependency>自动带进你的项目。也就是说,一个 Starter 的 POM 本身也是一个普通的“聚合描述文件”,它不包含多少代码,它的核心价值是明确地把一个技术场景所需要的 jar 清单固化下来。

3.2 版本锁定的魔力:BOM 与父 POM 的分工

“一个依赖就够了”这句话能成立,还有一个隐藏大前提:版本是谁定的?如果你什么都不加,只用 starter-web,但你也没继承spring-boot-starter-parent父 POM,那这个坐标的版本你还是得自己写。

在实际项目中,有两种常见做法,它们的原理是一样的,就是通过依赖管理(dependencyManagement)统一版本:

方式一:继承 starter-parent

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.4</version> <relativePath/> </parent>

一旦继承了它,你的子模块里所有官方的spring-boot-starter-*都不需要写<version>,因为父 POM 里已经通过<dependencyManagement>把版本号全部声明好了。这是绝大多数 Spring Boot 项目的标配做法。

方式二:引入 BOM,不继承父 POM

如果你不想继承 starter-parent(比如你的公司内部已经有一个统一父 POM),可以考虑在<dependencyManagement>里单独导入 BOM:

<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.3.4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

两种方式的底层都一样:spring-boot-dependencies(BOM)里面维护了 Spring Boot 所有支持组件版本号的约束列表。它的版本表信息非常全,比如 Spring Data 的版本、Netty 的版本、Jackson 的版本,全都对齐了,是经过 Spring Boot 官方发布前测试的。

我做项目时比较推荐方式二,尤其是微服务多模块项目,因为继承 pin 死了父 POM。BOM 导入像一个“约束模板”,你可以同时导入多个 BOM,如果再引入一个第三方 BOM,注意把自定义的放前面,保证优先覆盖。这个会在后面的常见问题里细讲。

3.3 自动配置的“条件化加载”:聪明地懒加载

前面说到了装载不等于生效,这里展开讲。Spring Boot 的自动配置类里大量使用条件注解,这些注解是 Starter 不产生副作用的关键。

核心的条件注解有这些:

注解作用
@ConditionalOnClass当类路径下存在指定类时,配置才生效
@ConditionalOnMissingBean当容器中不存在指定 Bean 时,才创建这个 Bean
@ConditionalOnProperty当某个配置属性存在且满足值时,配置才生效
@ConditionalOnWebApplication当前应用是 Web 应用时,配置生效
@ConditionalOnExpression满足 SpEL 表达式时生效

拿 spring-boot-starter-data-redis 来说,它的自动配置类RedisAutoConfiguration上面标注了@ConditionalOnClass(RedisOperations.class)。假如你的项目没用 Redis,而只是依赖里不小心带进来一个包含 Redis 客户端的 jar,这个自动配置类也不会激活,因为它检测不到RedisOperations类。这样就不会出现“我没想用 Redis,结果项目启动时报 redis 连接失败”之类的诡异现象。

顺着这个思路,你就能理解为什么引入 starter-web 之后,你写 RESTAPI 就能直接用了,却不需要自己配置DispatcherServlet:因为WebMvcAutoConfiguration这个自动配置类在类路径检测到DispatcherServlet类后,会通过一系列@Bean方法把核心组件定义好。而如果你自己想覆盖某个组件,只需要在@Configuration类里手动声明一个同名同类型的 Bean,@ConditionalOnMissingBean就会让你定义的优先生效。

这个设计解决的痛点是什么?是“配置文件的复杂度问题”。之前在 Spring 4 时代,如果你要跑一个 Spring MVC 项目,要配置 web.xml、要写@EnableWebMvc、要配视图解析器、配 Jackson 序列化器,全部手工来。Starter 把这些问题全部吞进 auto configuration,造成的差距就是:配置工作量从半天降到 5 分钟。

4. 核心实操:用项目验证“一个依赖就够了”

4.1 前置准备

我本机环境是 JDK 17(Spring Boot 3.x 要求 Java 17 以上)、Maven 3.9、IDEA 2024.1。你如果想跟着跑一遍,最好保持一致,至少 Java 版本要在 17 及以上,不然 Spring Boot 3.x 是不能跑的。

如果你用的是 IntelliJ IDEA 社区版,没有 Spring Initializr 按钮,也别急,可以直接去 start.spring.io 生成项目压缩包,或者更简单就手工创建一个 Maven 项目,把 pom 写进去,效果一样。我的建议是:今天这段至少值得打开 IDEA 跑一次,因为只有亲眼看到 31 个 jar 被传递依赖带进来,你才能真正感受到“一个依赖”的分量。

4.2 创建项目:核心 POM 长成什么样

我用 IDEA 自带工具创建了一个空的 Maven 项目,修改后的 pom.xml 如下:

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.4</version> <relativePath/> </parent> <groupId>com.example</groupId> <artifactId>starter-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

然后写一个最简单的启动类:

package com.example.starterdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class StarterDemoApplication { public static void main(String[] args) { SpringApplication.run(StarterDemoApplication.class, args); } @GetMapping("/hello") public String hello() { return "Hello, Starter!"; } }

启动main方法,控制台打出Tomcat started on port 8080,然后访问http://localhost:8080/hello,能够看到返回值。到这里,一个最简单 REST 接口已经跑通了。

这个过程中,我们没有写任何DispatcherServlet配置、没有写任何@EnableWebMvc,甚至没有手动指定 Tomcat 端口。全部由spring-boot-starter-web的自动配置完成。

4.3 眼见为实:在依赖树里“解剖”一个 Starter

项目跑通之后,在 IDEA 右侧 Maven 工具窗口中执行命令:

mvn dependency:tree -Dverbose

输出的内容里,你会看到类似这样的结构:

[INFO] com.example:starter-demo:jar:0.0.1-SNAPSHOT [INFO] \- org.springframework.boot:spring-boot-starter-web:jar:3.3.4:compile [INFO] +- org.springframework.boot:spring-boot-starter:jar:3.3.4:compile [INFO] +- org.springframework.boot:spring-boot-starter-json:jar:3.3.4:compile [INFO] | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.17.1:compile [INFO] | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.17.1:compile [INFO] | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.17.1:compile [INFO] +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.3.4:compile [INFO] | +- org.apache.tomcat.embed:tomcat-embed-core:jar:10.1.28:compile [INFO] | +- org.apache.tomcat.embed:tomcat-embed-el:jar:10.1.28:compile [INFO] | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:10.1.28:compile [INFO] +- org.springframework:spring-web:jar:6.1.12:compile [INFO] +- org.springframework:spring-webmvc:jar:6.1.12:compile

看到没有?spring-boot-starter-web这个节点下面,所有子依赖都被拉出来了。Tomcat 是嵌入式的,Jackson 用于 JSON 序列化,Jackson 的三个模块(Jdk8、JSR310、ParameterNames)也都是新版,其中jsr310用于 Java 8 时间类型和 JSON 之间的互相转换。如果手写这些坐标,版本号你要全部操心一遍,但用 Starter 一个都不用写。

如果想知道为什么版本号是 2.17.1 而不是 2.17.0,可以直接到spring-boot-dependenciesBOM 里去看。本地 Maven 仓库里,这个 BOM POM 文件在org/springframework/boot/spring-boot-dependencies/3.3.4/下,打开就能查所有组件版本约束。

4.4 一个 Spring Boot 3.x 项目引入数据库 Starter:更完整的例子

只跑一个 starter-web 可能感觉还不过瘾,我再加一个数据库场景。我在这里加入 MyBatis 场景介绍,因为这是国内 Java 项目里最常见的组合,也是热搜词里经常提到的东西。

引入 MyBatis 的起步依赖:

<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency>

引入 MySQL 驱动(这个不属于 Starter,就是普通驱动):

<dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency>

application.yml 再写上数据源信息:

spring: datasource: url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.starterdemo.entity

一个 Mapper 接口写在 java 目录下,对应 XML 放在 resources/mapper 下,项目启动时 MyBatis 自动配置类会扫描到它们。这就是 mybatis starter 起的作用:它监听到SqlSessionFactory类存在,同时容器里有了DataSourceBean,就自动创建SqlSessionFactory,再通过@MapperScan(或注解)扫描 Mapper 接口。你完全不用手工写SqlSessionFactoryBean。

注意:mybatis-spring-boot-starter 也是需要在<dependencyManagement>之外写版本号的。因为它不在 Spring Boot 官方 BOM 里。它的版本兼容矩阵是 MyBatis 社区维护的,如果你用的是 Spring Boot 3.3.x,就选 mybatis-spring-boot-starter 3.0.x;如果你还在用 Spring Boot 2.7.x,那就得选 2.3.x 或 2.2.x。对应关系千万别搞反,老项目直接升 Boot 3 然后沿用 MyBatis starter 2.x,成绩就是启动报错。

4.5 观察自动配置是否生效:一个非常实用的小命令

如果有一次你不确定某个 Starter 的自动配置到底有没有起作用,可以在application.yml或启动参数里加这个配置:

debug: true

启动后,控制台会打出一份Positive matches和Negative matches的自动配置报告。Positive 是明确生效的自动配置类,Negative 是没生效的。像这样:

Positive matches: WebMvcAutoConfiguration - @ConditionalOnClass 找到 Servlet、DispatcherServlet、WebMvcConfigurer 等类(OnClassCondition) Negative matches: RedisAutoConfiguration - 未找到 RedisOperations 类(OnClassCondition)

这个功能在排查“为什么我引了依赖但没效果”时是神器。排查思路就是我下面要聊的重点。

5. 常见问题与排查技巧实录

5.1 “引了依赖但自动配置没生效”怎么办

这个问题在开发中非常常见。大部分情况都出在条件注解上。第一次遇到这种情况时,我花了两三个小时查代码,最后才发现根本不是代码问题,而是 jar 根本没拉进来。

排查步骤建议这样走:

  1. 检查是否有AutoConfiguration.imports文件:进入本机 Maven 仓库对应 jar 目录,用压缩工具打开 jar,查看META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,如果没有这个文件,说明这个“Starter”不是一个规范的 Spring Boot 自动配置库。
  2. 打开 debug 报告:在application.yml里开debug: true,看目标自动配置类出现在 Positive 还是 Negative,再对照 Negative 的原因,比如“没有找到某个类”“条件属性不匹配”。
  3. 检查是否被自定义配置覆盖:如果你的项目里自己也定义了一个同名 Bean,比如定义了一个RestTemplate,spring-boot-starter-web 就不会再自动创建默认的RestTemplate(其实默认的也不算自动创建,需要额外建 Bean)。这是@ConditionalOnMissingBean的逻辑。

举个例子:第一次用spring-boot-starter-data-redis,我在项目里定义了一个自定义连接工厂RedisConnectionFactory,结果 redis 功能起不来。后来把 debug 打开,看到报告显示RedisAutoConfiguration因为@ConditionalOnMissingBean(RedisConnectionFactory.class)被跳过,这才反应过来,其实没必要自己定义,默认的 lettuce 连接工厂已经够用。

5.2 版本冲突:多个 BOM 混用时的优先级

Spring Boot 3.x 项目经常需要跟其他中间件联合使用,比如 Spring Cloud Alibaba、Dubbo,或者是某个内部封装的基础库,它们往往也提供自己的 BOM。于是会出现多个 BOM 同时约束同一个组件版本的情况,最难受的问题就是Netty 版本冲突、Jackson 版本冲突。

Maven 处理<dependencyManagement>的规则是:先声明的优先,并且子项目的声明优先于父 POM。所以如果你的 pom.xml 里<dependencyManagement>中先声明了自己的 BOM,那么就以你的为准。遇到版本冲突时不用抓瞎,直接在<dependencyManagement>最前面把你需要固定版本的坐标和版本号写进去,就能强制锁定。

还有另一个坑:传递依赖导致的 jar 冲突,比如某依赖强制引入了低版本 Jackson,你可能就需要用<exclusions>排除掉。尽量别用什么 mvn 命令去改全局版本,那不优雅,还是优先在 BOM 层级解决。

5.3 常见异常速查表

异常现象根本原因解决方案
启动报ClassNotFoundException: javax.servlet.*使用了 Spring Boot 2.x 或老 jar,依赖的还是 javax 命名空间升级到 jakarta 命名空间的依赖包;Spring Boot 3.x 只支持 jakarta
引入多模块项目,基础模块的 Starter 版本错乱子模块没有统一继承父 POM 或没有导入 BOM检查每个模块的父 POM,尽量统一用 spring-boot-starter-parent
MybatisAutoConfiguration报找不到SqlSessionFactory数据源配置缺失,或 mybatis starter 版本与 Boot 3 不兼容检查 datasource 配置与 mybatis starter 版本对应关系
自定义ObjectMapper不生效JacksonAutoConfiguration的@ConditionalOnMissingBean被满足,认为容器已有自定义的,不会再帮你配确保自定义 ObjectMapper 上标注@Bean,且类路径在自动配置扫描之前;如果不行,排除自动配置类
项目启动很慢,加载了一堆不该加载的自动配置spring-boot-starter 传递依赖带入了不需要的组件只按需引入必要的 starter,非必要的可以排除传递依赖或调整 debug 报告分析

5.4 一个易被忽略的点:Starter 不是越多越好

很多教程里把“引一个 starter 就能用”说得神乎其神,导致新手容易走向另一个极端,恨不得把几十个 starter 全塞进一个模块里。这是大忌。

每引入一个 Starter,等于引入了一批可能被自动激活的配置组件。只被启动而未被用到的自动配置类,虽然大部分条件注解会挡住它的加载,但不是所有组件都会按需关闭,有些组件还是会占用初始化时间、端口探测、连接池创建,甚至时机不对还会报错。比如你把spring-boot-starter-data-jpa引了进来但完全不配数据源,项目启动的默认数据源初始化流程还是会去构建一个 DataSource Bean,导致启动失败。

我的经验是:一个技术场景对应一个 Starter,能不引就不引;如果某个功能一段时间不用,宁可分隔成独立服务,也不要全部堆在同一个 Web 工程里。这也是微服务拆分的核心动机之一,依赖隔离能让启动速度和问题排查都更清爽。

6. 踩坑过后总结的实操心得

最后分享几个我自己较有价值的实操体会。

第一,Starter 版本不是越新越好,而是和 Spring Boot 主版本匹配。Spring Boot 3.3.x 项目,最好使用与之配套的第三方 starter 新版本。比如 MyBatis starter 3.0.x 就是为 Boot 3 准备的。如果你只看“网上教程写的旧版本号”,会有很多坑。我现在处理版本问题的第一反应永远是去官方文档查 Spring Boot 版本兼容矩阵,而不是试错试到晚上。

第二,理解@SpringBootApplication里那三个注解的分工。它其实是由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan组合出来的。自动配置的核心是@EnableAutoConfiguration。如果你在某些模块里没有加@SpringBootApplication,那自动配置就完全不会发生,你引入的 starter 就只是一个普通 jar,什么都不会发生。这一点我之前在一个多模块项目里吃过亏,子模块里写了 @Configuration,但没加 @EnableAutoConfiguration 或 @SpringBootApplication,导致 RedisTemplate 一直为 null。

第三,如果用exclusions排除传递依赖,记得在注释里说明排除原因。否则三个月后你回头看 pom,完全想不通当时为什么要那么写。我自己吃过这个亏,曾在 pom 里排除了某个库的旧 netty,后来新同事不知道原因,又把旧版本坐标加回来,结果线上问题,查了两天才定位。

第四,一定要利用好Spring Boot 3.x 的自动配置报告。我前几年特别喜欢在项目出问题时直接搜网上“为什么 Redis 自动配置不生效”,但效率极低。现在我的做法是:debug: true一开,正负匹配报告一拉,对照着条件注解看,问题原因基本能在十分钟内定位。工具就在身边,用好它比到处查答案靠谱得多。

如果你还在学习 Spring Boot 的阶段,不妨试着自己写一个极简的自定义 Starter 出来——一个 jar 里放一个自动配置类和一个 imports 文件,在另一个工程里引入,会发现整个过程通透很多。毕竟,真正理解一个机制最有效的方式,就是亲手还原一遍它。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询