Spring Boot 4 技术栈纵览:Starter 粒度、MVC 版本协商与安全演进#
摘要:Spring Boot 4 与 Spring Framework 7 组合下,依赖可按能力拆成更细的 Starter,Web 出站客户端可与服务端 MVC 依赖分离;同一代码库可在 Spring MVC 中启用内置 API 版本解析,并与 Spring Data JDBC、RestClient / 声明式 @HttpExchange 客户端协同。Spring Security 7 侧重可叠加的 Customizer<HttpSecurity>、一次性令牌登录、WebAuthn 与注解式多因子模型;配合 JVM AOT 与 Spring Data JDBC 的编译期仓储片段,可将启动路径向「训练—缓存—回放」方向推进,但参数需与 JDK、模块开关严格对齐。下文按依赖层与安全边界展开,示例坐标以当前 Initializr 与参考手册为准;配图中所见的 Boot 4.1.0 (SNAPSHOT) 与稳定线 4.0.x 并存时,以所选 BOM 为准。

Spring Boot integration for RestClient and RestTemplate to make HTTP requests,以及 PostgreSQL Driver 段落的 A.JDBC and R2DBC driver that allows Java programs to connect to a PostgreSQL database。

GraalVM Native Support 说明文字 Support for compiling Spring applications to native executables using the GraalVM native-image,以及 Spring Modulith 条目 Support for building modular monolithic applications。
1. Spring Boot 4:Starter 重组与出站 HTTP 依赖分离#
(1) 原理与动机
Boot 4 将「按技术拆 Starter」作为常态:Classpath 上仅引入所需技术的 starter,可减少无关自动配置类的装载面。典型诉求是:构建基于 Servlet 的 Web 应用与「只做出站 HTTP 调用」可选用不同 starter,避免在无服务端场景拖入嵌入式 Web 容器相关配置。
(2) 实现抓手
- Spring Initializr 依赖元数据 将依赖 ID 映射到具体 Maven 坐标;Initializr 界面仍可能出现
spring-boot-starter-web等历史文案与 Boot 4 命名演进并存的现象,工程应以生成器输出的spring-boot-starter-webmvc、spring-boot-starter-restclient(依赖 ID 常为spring-restclient)等为准。 - Spring Boot 4.0 迁移指南 — Starters 说明 starter 集合更一致、多数技术有专用 starter 及配套 test starter。
- Modulith:
org.springframework.modulith:spring-modulith-starter-core由 BOM 管理,可在同一单体中约束模块边界。
(3) 怎么用
<!-- 片段示意:仅出站客户端(坐标以 Initializr 生成为准) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-restclient</artifactId>
</dependency>
spring-boot-starter-restclient 与 RestClient.Builder bean 的装配细节见 Boot 参考手册「调用 REST 服务」一章。

2. Spring Data JDBC 与只读 HTTP API(/dogs)#
(1) 原理与动机
Spring Data JDBC 以聚合根为中心映射表行,适合中小型域模型快速暴露 CRUD。Java record 在存在与列名匹配的非零参构造器时,可按 JDBC 映射文档 的构造器绑定规则实例化实体。
(2) 实现抓手
- 仓储接口继承
ListCrudRepository。 - 控制器侧使用 Spring MVC 常规注解(
@GetMapping等)暴露 JSON。
(3) 怎么用
interface DogRepository extends ListCrudRepository<Dog, Integer> {}
@RestController
class DogsController {
private final DogRepository dogs;
DogsController(DogRepository dogs) { this.dogs = dogs; }
@GetMapping("/dogs")
Iterable<Dog> all() { return dogs.findAll(); }
}
curl -s http://localhost:8080/dogs

localhost:8080/dogs 与 [{"id":45,"name":"Prancer","owner":"josh","description":"A demonic, neurotic, man hating, animal hating。
3. Spring MVC:内置 API 版本协商#
(1) 原理与动机
在同一部署内并行维护多版本处理器时,需要在请求解析阶段确定版本、拒绝非法版本并可对接弃用提示。Spring Framework 7 提供统一的 ApiVersionConfigurer 编程入口;Boot 则用 spring.mvc.apiversion.* 将常见策略映射为应用属性。
(2) 实现抓手
| 机制(文档用语) | Boot 属性键(附录中出现) |
|---|---|
| 请求头 | spring.mvc.apiversion.use.header |
| 查询参数 | spring.mvc.apiversion.use.query-parameter |
完整键名见 Boot Application Properties;策略总览见 MVC API 版本解析。
(3) 怎么用
spring.mvc.apiversion.default=1.1
# 自定义头名仅为演示约定;生产环境请与网关及客户端统一命名
spring.mvc.apiversion.use.header=X-Dogs-Version

application.properties 编辑区可见 spring.mvc.apiversion.default=1.1 与关于 spring.mvc.apiversion.use.header 的 IDE 提示行 (Use the HTTP header th。
curl -s http://localhost:8080/dogs
curl -s -H "X-Dogs-Version: 1.0" http://localhost:8080/dogs
默认版本与显式头在两套请求中的路由差异,可通过 @RequestMapping 等映射注解上的版本约束观察;属性值类型以 Boot 属性附录为准。
4. RestClient 与声明式 @HttpExchange 客户端#
(1) 原理与动机
出站调用既可命令式构造 RestClient,也可用带 @HttpExchange / @GetExchange 的接口由 HttpServiceProxyFactory 生成代理,以便用类型契约约束远程调用。Framework 7 起 RestTemplate 已标记弃用,新项目优先 RestClient。
(2) 实现抓手
- Boot:RestClient.Builder bean 与定制器。
- 注解:
GetExchangeJavadoc。 - 应用入口常用
@Import注册HttpServiceProxyRegistry相关配置(具体类的包名以当前 Framework 版本为准)。
(3) 怎么用
客户端接口(示例:第三方 HTTP API,URI 请替换为真实端点):
interface CatFactsClient {
@GetExchange("https://example.catfacts/api")
CatFacts facts();
}
服务端聚合(避免「只写请求不写处理侧」):
@RestController
class CatsController {
private final CatFactsClient client;
CatsController(CatFactsClient client) { this.client = client; }
@GetMapping("/cats")
CatFacts cats() { return client.facts(); }
}

@Import 参数片段 (CatFactsClient.class) 以及 import org.springframework.web.service.annotation 等行。

import org.springframework.web.service.registry 与注解 (CatFactsClient.class) 靠近 SpringApplication.run。
5. BeanRegistrar 程序化注册 Bean 与 JSpecify @NullMarked#
(1) 原理与动机
静态 @Bean 方法不足以表达「按环境或循环批量注册」时,BeanRegistrar 在 register(BeanRegistry, Environment) 中增量声明 Bean,典型搭配 @Import(MyRegistrar.class)。与此同时,org.springframework.beans.factory 包级 @NullMarked 将默认空安全语义收紧为「非空除非 @Nullable」,与 JSpecify @NullMarked 定义 一致。
(2) 实现抓手
BeanRegistrar、BeanRegistry.registerBean(...)。- JSpecify 入门站点以 jspecify.dev 为准(注解语义以源码/JavaDoc 为准)。
(3) 怎么用
@Configuration
@Import(DynamicBeans.class)
class AppConfig {}
class DynamicBeans implements BeanRegistrar {
@Override
public void register(BeanRegistry registry, Environment env) {
for (int i = 0; i < 4; i++) {
registry.registerBean(MyRunner.class);
}
}
}
record MyRunner() {}

registry.registerBean(MyRunner.class) 以及日志行 Tomcat started on port 8080 (http) with context path '/'。

BeanRegistrar、BeanRegistry,下部源码窗口含 public @interface NullMarked 与句子 For a comprehensive introduction to JSpecify, please see jspecify.org。
6. Spring Security 7:JDBC 用户存储与运行期边界#
(1) 原理与动机
Servlet 栈下,JdbcUserDetailsManager 在 UserDetailsManager 语义上扩展 JdbcDaoImpl,便于以数据库行驱动认证主体。引入 Security 并不自动等价于某种固定用户模型;需显式提供 UserDetailsService / UserDetailsManager 与 SecurityFilterChain。
(2) 实现抓手
JdbcUserDetailsManager文档示例。HttpSecurityJava 配置 中的Customizer.withDefaults()。
(3) 怎么用
@Bean
SecurityFilterChain chain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests(a -> a.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults())
.build();
}
curl -s -o /dev/null -w "%{http_code}\n" -u user:pass http://localhost:8080/actuator/health

Global AuthenticationManager configured with UserDetailsService bean with name jdbcUserDetailsManager 与 Tomcat started on port 8080 (http)。
7. 可叠加的 Customizer<HttpSecurity>:一次性令牌登录与 WebAuthn#
(1) 原理与动机
Spring Security 7 允许以 Customizer<HttpSecurity> Bean 增量拼装 DSL,而不必整体替换默认过滤器链形态。一次性令牌登录(OTT)将魔法链接式登录纳入 oneTimeTokenLogin,默认交互路径包含 /login/ott。WebAuthn / Passkeys 则在 http.webAuthn 上配置 RP 名称、RP ID 与 allowedOrigins,以匹配浏览器 ceremony 的来源约束。
(2) 实现抓手
- OTT:DSL、
DefaultOneTimeTokenSubmitPageGeneratingFilter相关描述见同一手册页。 - Passkeys:依赖可选
spring-security-webauthn(Initializr 映射见 依赖 JSON)。
(3) 怎么用
@Bean
Customizer<HttpSecurity> httpSecurityCustomizer() {
return http -> http
.webAuthn(w -> w.rpName("spring").rpId("localhost")
.allowedOrigins("http://localhost:8080"))
.oneTimeTokenLogin(ott -> ott.tokenGenerationSuccessHandler((req, res, token) -> {
res.setContentType("text/plain;charset=UTF-8");
res.getWriter().println("please go to http://localhost:8080/login/ott?token="
+ token.getTokenValue());
}));
}

return HttpSecurity http — http.oneTimeTokenLogin( OneTimeTokenLoginConfigurer< 与控制台输出 please go to http: //localhost:8080/login/ott?token=aa26d038-edf0-420f。

http.webAuthn(、Customizer<HttpSecurity> httpSecurityCustomizer(),以及控制台重复的 please go to http: //localhost:8080/login/ott?token=aa26d038-edf0-420f。
8. 多因子认证:@EnableMultiFactorAuthentication#
(1) 原理与动机
注解模型将「密码因子 + 额外因子(如 OTT)」映射为框架识别的 FactorGrantedAuthority,缺因子时可导向已配置的 OTT 登录页。文档明确密码认证默认附带 FactorGrantedAuthority.PASSWORD_AUTHORITY;配图 OCR 中出现的噪声片段 ONETIME TOKEN_AUTHORITY 与官方常量命名并不一致,以手册与 FactorGrantedAuthority 为准。
(2) 实现抓手
@EnableMultiFactorAuthentication章节。- 典型示例:
@EnableMultiFactorAuthentication(authorities = { FactorGrantedAuthority.OTT_AUTHORITY })。
(3) 怎么用
@EnableMultiFactorAuthentication(authorities = { FactorGrantedAuthority.OTT_AUTHORITY })
@Configuration
class MfaConfiguration {}
浏览器端为多步交互;因子与 UserDetails 中 authority 的对应关系需在自有用户模型中落地。

class CatsController、class SecurityConfiguration,以及类型提示中的 Customizer <HttpSecurity> 与 HttpSecurity 继承层次片段。
9. JVM AOT、Spring Data JDBC 仓储片段与 Leyden 语境#
(1) 原理与动机
Boot 的 JVM AOT 处理 旨在用预先计算的初始化与缓存缩短启动路径;Spring Data JDBC 在 AOT 模式下可生成仓储实现片段(官方文档描述命名模板为 <Repository FQCN>Impl__Aot,并强调属内部优化)。OpenJDK Project Leyden 汇总多份 AOT 相关 JEP,与「训练运行—生成缓存—回放」同属一类优化范畴。示例运行日志中曾出现 AOT 缓存与模块属性不一致报错:需在 dump 与 runtime 阶段对齐 jdk.module.addmods 等 JVM 参数。
(2) 实现抓手
- Spring Data JDBC — AOT Repositories(Asciidoc 源码):
spring.aot.enabled、spring.aot.repositories.enabled、spring.aot.jdbc.repositories.enabled,以及「提供JdbcDialect以避免方言探测引发过早数据库访问」的建议。具体方言类型名应以所选数据库模块文档为准;若口头示例提到特定类名而公开手册未列出同名片段,应视为未在公开章节逐字核实。 - 生成类截图中的
DogRepositoryImpl__AotRepository与文档模板在字面后缀上可能因版本演进不完全一致,以当前构建产物为准。
(3) 怎么用
public interface DogRepository extends ListCrudRepository<Dog, Integer> {
Collection<Dog> findByName(String name);
}
构建与 JVM 参数须对照 Boot AOT 手册与 JDK 发行说明逐步校准。

public class DogRepositoryImpl__AotRepository extends AotRepositoryFragmentSupport 与方法 public Collection<Dog> findByName(String name)。

Reading AOTConfiguration app.aot.config and writing AOTCache app.aot 以及 [error][aot] Mismatched values for property jdk.module.addmods。

10. 工程落地:脚手架解压与依赖树核对#
(1) 原理与动机
示例工程从 Zip 解压后经 Maven Wrapper 构建;IDE 依赖树用于核对 Spring Framework 补丁版本、Jackson 主版本与 Modulith、Security 组件坐标,避免「本地可运行、CI 缺坐标」类问题。
(2) 实现抓手
- 通用:
unzip、./mvnw -q -DskipTests package。 - BOM:
spring-boot-dependenciesPOM 中的jackson-bom.version等属性可与依赖树交叉验证。
(3) 怎么用
unzip -q adoptions-springio.zip && cd adoptions-springio
./mvnw -q -DskipTests package

creating: adoptions-springio 与 inflating: adoptions-springio/pom.xml [binary]。

org.springframework:spring-core:7.0.6 与多行 org.springframework.modulith:spring-modulith-s。
参考与延伸阅读#
- Spring Initializr 依赖 ID 与 Maven 坐标索引
- Spring Boot 4.0 迁移指南(Starter 重组)
- Spring Boot 4.0 — 调用 REST 服务(RestClient 集成)
- Spring Framework — REST 客户端总览(RestClient、声明式 HTTP)
- Spring Framework — MVC API Version 编程配置
- Spring Framework —
@RequestMapping与 API 版本映射 - Spring Boot 4.0 — Application Properties(含
spring.mvc.apiversion.*) - Spring Data JDBC — 实体映射(Asciidoc 源码)
ListCrudRepositoryJavaDoc- Spring Framework —
BeanRegistrar接口源码(v7.0.6) - JSpecify —
@NullMarked注解源码(v1.0.0) - Spring Security — JDBC 认证与用户管理器
- Spring Security — One-Time Token Login
- Spring Security — Passkeys / WebAuthn
- Spring Security — Multi-Factor Authentication
- Spring Boot 4.0 — JVM 上的 Ahead-of-Time 处理
- Spring Data JDBC — AOT Repositories 章节(Asciidoc 源码)
- OpenJDK Project Leyden(AOT 相关 JEP 索引)
- Maven Central —
spring-boot-dependencies4.0.6 BOM(Jackson 等版本属性)



