在项目迭代中,对外开放的业务接口在迭代过程中除了添加新的业务逻辑,还需要同时兼容旧版本的业务逻辑,
即,新旧接口需要同时对外提供服务。

开发中通常的做法是通过指定不同版本号以此来区分不同版本的接口。
比如:下单接口 /place-order
通过 /v1/place-order/v2/place-order的方式来区分版本一和版本二的接口。

在开发中,可以直接通过 @RequestMapping注解的方式进行不同版本接口的资源声明,例如:
image.png
除了直接使用 API 的方式进行接口版本控制,还可以借助 Spring MVC 优雅的实现 API 版本控制,实现后代码效果图如下:
image.png
在功能实现上,两种并无区别。

不过借助 Spring MVC 框架扩展点做接口版本管理能够更好管控对接口版本的管理。

如:统一的版本控制定义。

当不在使用 v1/v2/的方式,而是使用 vv1/vv2的前缀进行版本控制能够快速的进行统一更改。

如:针对版本控制前缀还可以定制化处理。

当前存在 v1v2两个版本接口,在后期业务迭代中,两个接口业务再次合并,不在需要分离版本,此时可以在不变更前端API请求路径的前提下,移除 v2版本业务逻辑, 已有的针对 v2的请求全部路由到 v1中进行处理。

一、Spring MVC 回顾

《Spring MVC》中简单介绍了 Spring MVC 的工作原理。

Spring MVC 的工作重心就是存储:资源路径(即URL)方法实例(具体实现)之间的映射关系。

而完成这项工作的重要组件为: HandlerMappingHandlerMethod

下面从两个点回顾 Spring MVC HandlerMapping

  • 1、项目初始化时 HandlerMapping 初始注册HandlerMethod资源URL映射关系。
  • 2、请求时的 HandlerMapping 根据请求资源 URL 匹配获取HandlerMethod

    2.1、HandlerMapping 初始化注册 HandlerMethod,并进行映射

    资源 URL具体实例方法的映射关系存储在Map中, Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>(); 其中 T 通常为 RequestMappingInfo

集成 Spring MVC 后, 项目通过@RequestMapping("/xxx")标注资源路径。
资源路径URL和具体被标注的方法实例间的关系由 RequestMappingHandlerMapping来构造。

RequestMappingHandlerMapping通过实现 InitializingBean接口,在Spring IOC 容器启动过程中,通过调用 RequestMappingHandlerMapping#afterPropertiesSet方法对 RequestMappingHandlerMapping进行初始化处理,即解析由 @RequestMapping("/xxx")标注类及方法 并构造映射关系。

相关源码如下:
image.png
如上述代码,最终的解析在 detectHandlerMethods方法中完成。
部分代码如下:
image.png
如上述代码,解析后的映射对象

  • key 为:Method具体执行方法
  • value为:RequestMappingInfo资源映射信息

最后对 Method和其所在的类实例进行绑定,构建 HandlerMethod,而后和 RequestMappingInfo构建映射关系,存储在 Map 中。

2.2、根据资源URL 匹配 HandlerMethod

项目初始加载后,Spring MVC 将资源访问 URL(RequestMappingInfo)具体的实例方法(HandlerMethod)进行关系映射并存储在 map 中。

在资源访问时,Spring MVC 通过匹配 URL,匹配到对应的 HandlerMethod ,对应的拿到映射的实例方法,然后通过反射调用实例方法,实现URL访问对资源的调用。

Spring MVC 针对的资源处理统一入口为 Servlet,即:DispatcherServlet 。

对于 Servlet 来说,请求的入口即 doGet或者 doPost

以此作为源码入口,对应的处理流程如下图:
image.png
通过上图追踪代码,可知进行 URL 匹配的代码入口为 AbstractHandlerMethodMapping
具体进行 ULR 匹配的处理逻辑在 AbstractHandlerMethodMapping#lookupHandlerMethod中,部分代码如下:
image.png
通过代码追踪,具体的匹配方法在项目启动时构造的 RequestMappingInfo#getMatchingCondition中。
具体代码如下:
image.png
上述对应了 Spring MVC 不同的匹配规则。

而 API 版本控制的处理,即对 URL 匹配的处理,通过自定义相关的匹配规则即可完成对应的 API 版本 URL 的处理

通过匹配到对应的 RequestMappingInfo从而从映射关系中获取到 HandlerMethod,再通过调用 HandlerMethod标注的资源方法实现资源访问。

二、自定义 URL 匹配实现API版本控制

通过引入自定义匹配规则,实现 API 版本管理 参考方法:RequestMappingHandlerMapping#getCustomTypeCondition。 参考方法:RequestMappingHandlerMapping#getCustomMethodCondition

spring-boot-api-version.zip.txt

2.1、项目结构

image.png

2.1.1、匹配规则实现 ApiVersionCondition

关键代码
image.png

2.1.2、自定义 HandlerMapping 注册 Condition

关键代码 CustomRequestMappingHandlerMapping如下:
image.png

2.1.3、使用案例

image.png