Spring Boot Starter 原理
候选人小周在面试美团P6时,简历上写着"熟练使用 Spring Boot,有 spring-boot-starter-web 开发经验"。
面试官问:"你用过 spring-boot-starter-web,那你知道它里面包含什么代码吗?"
小周说:"包含 Web 服务器、Spring MVC 相关的依赖吧?"面试官追问:"那 starter 本身有多少代码?"小周答不上来。面试官又问:"spring-boot-starter-web 和 spring-boot-starter 是什么关系?"
小周支支吾吾,最后说:"后者是基础包?"
【面试官心理】
这道题我用来测试候选人对 Spring Boot "依赖传递"和"配置解耦"的理解程度。知道 starter 是一个纯依赖集合的占 60%,能说出自动配置类加载机制的占 30%,能讲清楚 Spring Boot 3.x 变化的只有 10%。这道题真正区分了"会用"和"会设计"。
一、Starter 到底是什么 🔴
1.1 Starter 的本质:一组依赖坐标
Spring Boot 的 Starter 本身不包含任何 Java 代码。它的本质就是一个 Maven pom.xml,里面定义了一堆依赖坐标。
所有真正的代码逻辑都在被依赖的那些 jar 包里。spring-boot-starter-web 只是把它们组装起来。
1.2 Starter 的命名规范
Spring Boot 官方对 Starter 的命名有严格规范:
命名规范不是强制的,但遵循规范能让使用者一眼就知道这个 starter 是官方的还是第三方贡献的。*-spring-boot-starter 的命名在 Maven central 上有更好的搜索可见性。
1.3 依赖传递链路
注意看:spring-boot-autoconfigure 才是真正包含自动配置逻辑的地方。spring-boot-starter-web 通过传递依赖把它引入进来。
二、Starter 的自动配置机制 🟡
2.1 自动配置类在哪里
spring-boot-autoconfigure jar 包中包含了所有自动配置类:
每个自动配置类都标注了 @Conditional 系列条件注解,只有满足条件才会注册到容器中。
2.2 配置类的加载
自动配置类通过 spring.factories(Spring Boot 2.x)或 AutoConfiguration.imports(Spring Boot 3.x)被 Spring Boot 发现。
三、Fatjar 结构 🟡
3.1 spring-boot-maven-plugin 的作用
当你在 pom.xml 中配置了 spring-boot-maven-plugin:
打出来的 jar 包结构是这样的:
spring-boot-maven-plugin 做了两件事:
- 把所有依赖 jar 解压,将内容合并到一个扁平的 jar 中
- 添加一个
JarLauncher类,用于加载BOOT-INF/lib/下的依赖
这就是为什么 Spring Boot 的 jar 可以用 java -jar app.jar 直接运行,而传统 Maven jar 必须指定 classpath。因为 Spring Boot 的 jar 本身就是可执行的。
3.2 JarLauncher 的类加载策略
传统 Java 的类加载器只能加载文件系统上的 jar 文件。Spring Boot 的 JarLauncher 配合自定义的 LaunchedURLClassLoader,可以加载 jar 包内部的 jar(nested jar)。
四、Spring Boot 3.x 的变化 🟡
Spring Boot 3.x 最大的变化是从 javax 命名空间迁移到了 jakarta。这意味着如果你引用了 Spring Boot 3.x 的 starter,所有依赖的 Servlet/JAXB 等都必须是 jakarta.* 版本。
五、❌ 错误示范
5.1 把 Starter 当成框架
候选人原话:"spring-boot-starter-web 是一个框架,里面有 Spring MVC、Tomcat、Spring Boot 的核心代码。"
问题诊断:
- 不理解 Starter 的本质是依赖聚合,不是代码库
- 不理解"自动配置"和"框架代码"的区别
面试官内心 OS:"这个候选人估计连 Maven dependency:tree 都没跑过。"
5.2 不知道自动配置在哪里
候选人原话:"Spring Boot 的自动配置是 Spring Boot 框架自己做的,不需要额外配置。"
问题诊断:
- 不知道 spring-boot-autoconfigure 的存在
- 不知道自动配置类是有条件触发的
- 不知道 spring.factories 或 imports 文件的作用
5.3 版本混淆
候选人原话:"Spring Boot 3.x 还是用 spring.factories,只是位置变了。"
问题诊断:
- 记混了 2.7 和 3.x 的区别
- 2.7 开始引入了 imports,3.x 才完全移除了 spring.factories
六、标准回答
6.1 P5 级别
"Spring Boot Starter 是一组预定义的依赖集合。比如 spring-boot-starter-web 包含了 spring-boot-starter、spring-boot-starter-tomcat、spring-web、spring-webmvc 等依赖,让开发者只需要引入一个 starter 就能搭建 Web 项目。"
6.2 P6 级别
"Starter 本身不包含任何 Java 代码,它只是一个 pom.xml 定义了一组依赖坐标。真正的自动配置逻辑在 spring-boot-autoconfigure 包中,通过 spring.factories(2.x)或 AutoConfiguration.imports(3.x)声明。
Spring Boot 的启动依赖传递链路是:spring-boot-starter-web → spring-boot-starter → spring-boot-autoconfigure。spring-boot-autoconfigure 中的每个配置类通过 @Conditional 条件注解决定是否生效。
打出来的 jar 由 spring-boot-maven-plugin 打包成 fatjar 结构,包含 BOOT-INF/classes(项目代码)和 BOOT-INF/lib(所有依赖),由 JarLauncher 负责加载。"
6.3 P7 级别
"Starter 机制体现了 Spring Boot 的核心设计理念:'约定大于配置'。框架作者预先写好配置类,用户只需要引入 starter 依赖就能开箱即用。
我之前参与设计过公司的内部 starter,发现最大的坑是:starter 的 spring.factories 或 imports 文件必须由 spring-boot-autoconfigure 统一扫描。如果 starter 自己声明了重复的配置类,Spring Boot 2.7 之前可能会被全局扫描覆盖,2.7 之后收敛到了 imports 文件的范围内。
Spring Boot 3.x 的 jakarta 迁移是个大工程,我们当时升级时,Spring Security、Jackson 等所有引用 javax.servlet 的库全都要换成 jakarta 版本,光依赖排查就花了一周。"
【面试官心理】
P7 的回答重点在于"设计理念"和"踩坑经历"。知道 Starter 是依赖聚合只是基本操作,能说出"为什么这么设计"和"踩过什么坑"的才是真正有深度的候选人。