Spring 中的 API 版本控制

工程 | Rossen Stoyanchev | 2025年9月16日 | ...

在这篇“通往 GA 之路”系列的第二篇博客文章中,我将重点介绍 Spring Framework 7 中即将推出的 API 版本控制支持,该系列旨在强调 Spring 组合中将于 11 月发布的下一个主要版本中的主要功能。

引言

API 版本控制是一个具有挑战性的话题。大多数文章列出了各种实现方式,但没有提供建议。当提供建议时,范围广泛。例如,Roy Fielding建议反对。它是一种常见且广泛使用的实践,但关于如何做或是否做,却没有标准或共识。

此外,不同的应用有不同的需求,这些需求取决于业务领域、公司动态、演进阶段等,因此需要考虑已发布的建议如何适用于您自己的特定情况。

所有这些,再加上通过 @RequestMapping 注解表达各种方式(路径、头部、媒体类型等)并不太难,实际上意味着 Spring 之前没有官方支持,直到现在。发生了什么变化?

正如新功能通常的情况一样,它们始于用户请求,这次请求指出,虽然在 Spring 应用程序中实现 API 版本控制是可能的,但实际上需要大量工作。回顾总括问题的子任务,这确实是一个有效的观点。自那时起我们在这个话题上看到的反馈和兴趣数量进一步表明了明确的需求。

这篇博文的目的不是进一步讨论 API 版本控制实践。有关该主题的更长介绍,您可以观看我在今年早些时候的 Spring I/O 会议上的演讲。

通常,此功能的目的是为这种非常常见的实践和需求提供必要的构建块。

服务器处理

服务器端处理的核心是 ApiVersionStrategy,这是一个关键契约,它了解所有应用程序的 API 版本控制偏好。它可以解析、分析和验证请求版本;它了解支持的版本范围;并且可以帮助在响应中发送弃用提示。

您可以通过MVC 配置WebFlux 配置来配置它。例如

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

	@Override
	public void configureApiVersioning(ApiVersionConfigurer configurer) {
		configurer.useRequestHeader("API-Version");
	}
}

对于 Spring Boot 应用程序,有等效的属性。例如

spring.mvc.apiversion.use.header=API-Version

一旦配置完成,它就可以用于在请求处理中支持 API 版本控制。

对于带注解的控制器,您可以使用 @RequestMapping 注解的新 version 属性及其专用形式,例如 @GetMapping

@RestController
public class AccountController {

	@GetMapping(path = "/account/{id}", version = "1.1") 
	public Account getAccount() {
	}
}

对于函数式端点,您可以使用 version 请求谓词

RouterFunction<ServerResponse> route = RouterFunctions.route()
	.GET("/hello-world", version("1.2"),
		request -> ServerResponse.ok().body("Hello World")).build();

如果 API 版本位于请求头、查询参数或媒体类型中,则在映射中无需做任何其他事情。

如果 API 版本位于路径中,则必须将其声明为 URI 变量(可以使用任何名称),例如“/api/{version}”。通常,最好通过路径匹配选项将其作为所有处理程序的通用路径前缀进行外部配置,这样就不需要在每个映射中重复它。

默认情况下,请求版本被解析为包含主版本、次版本和补丁值的语义版本,如果次版本和补丁版本不存在,则设置为 0。这对于能够比较版本很重要。如果您想使用日期或任何其他格式,可以自定义或替换解析器。

在映射中,版本可以是固定版本,例如“1.2”,也可以是基线版本,例如“1.2+”。基线版本在以下场景中非常有用:增量更改应用于选定的端点,从而无需为未更改的端点创建额外的控制器方法。

例如,给定支持的版本“1.2”和“1.3”,版本为“1.2+”的控制器方法同时支持这两个版本。这允许控制器方法在版本 1.3 和其他未来版本中继续工作,直到在更高版本中需要新的控制器方法。

版本控制的一个重要方面是向客户端提供弃用提示。您可以配置一个弃用处理器来完成此操作。内置处理器可以根据 RFC 9745RFC 8594 设置“Deprecation”、“Sunset”和“Link”头。

客户端支持

从客户端的角度来看,您可能需要使用 API 版本执行请求。为此,有一个 ApiVersionInserter,它决定如何一次将版本插入请求中,随后当您发出请求时,您只需指定版本值。

例如,在 RestClientWebClient 中,您可以设置一个插入器

RestClient client = RestClient.builder()
		.baseUrl("https://:8080")
		.apiVersionInserter(ApiVersionInserter.useHeader("API-Version"))
		.build();

对于 Spring Boot 应用程序,有等效的属性。例如

spring.http.client.restclient.apiversion.insert.header=API-Version

然后按如下方式执行请求

Account account = client.get().uri("/accounts/1")
		.apiVersion(1.1)
		.retrieve()
		.body(Account.class);

HTTP 接口客户端通过 @HttpExchange 注解的新 version 属性及其专用形式(例如 @GetExchange 等)支持 API 版本控制。例如

@HttpExchange("/accounts")
public interface AccountService {

	@GetExchange(url = "/{id}", version = "1.1")
	Account getAccount(@PathVariable int id);

}

测试

正如您所料,API 版本控制也适用于测试,例如与 RestTestClient(7.0 版新增)和 WebTestClient 一起使用。

两者都是实际的客户端,类似于 RestClientWebClient,因此需要配置客户端 ApiVersionInserter 以相应地准备请求。它们还配置服务器端,但这取决于所选的设置,如下所示

在不使用测试客户端的情况下直接使用 MockMvc 进行测试时,也支持 API 版本控制。您可以配置 ApiVersionInserter 来初始化 MockHttpServletRequest,并在使用独立设置时配置 ApiVersionStrategy

如果您想在 Spring Boot 测试场景中查看上述一些内容,请查看此示例项目中的测试

总结

在这篇博文中,我们简要介绍了 Spring Framework 7 中即将推出的 API 版本控制支持。

有关更多详细信息,请查阅参考文档的相关部分。您还可以尝试这个示例项目

如果您有 API 版本控制要求,请查看并在此处或通过我们的问题跟踪器联系我们(如果需要)。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看所有