在项目迭代中,对外开放的业务接口在迭代过程中除了添加新的业务逻辑,还需要同时兼容旧版本的业务逻辑,
即,新旧接口需要同时对外提供服务。
开发中通常的做法是通过指定不同版本号以此来区分不同版本的接口。
比如:下单接口 /place-order
。
通过 /v1/place-order
和 /v2/place-order
的方式来区分版本一和版本二的接口。
在开发中,可以直接通过 @RequestMapping
注解的方式进行不同版本接口的资源声明,例如:
除了直接使用 API 的方式进行接口版本控制,还可以借助 Spring MVC 优雅的实现 API 版本控制,实现后代码效果图如下:
在功能实现上,两种并无区别。
不过借助 Spring MVC 框架扩展点做接口版本管理能够更好管控对接口版本的管理。
如:统一的版本控制定义。
当不在使用
v1/v2/
的方式,而是使用vv1/vv2
的前缀进行版本控制能够快速的进行统一更改。
如:针对版本控制前缀还可以定制化处理。
当前存在
v1
、v2
两个版本接口,在后期业务迭代中,两个接口业务再次合并,不在需要分离版本,此时可以在不变更前端API请求路径的前提下,移除v2
版本业务逻辑, 已有的针对v2
的请求全部路由到v1
中进行处理。
一、Spring MVC 回顾
在《Spring MVC》中简单介绍了 Spring MVC 的工作原理。
Spring MVC 的工作重心就是存储:资源路径(即URL)
和 方法实例(具体实现)
之间的映射关系。
而完成这项工作的重要组件为: HandlerMapping
和 HandlerMethod
下面从两个点回顾 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")
标注类及方法 并构造映射关系。
相关源码如下:
如上述代码,最终的解析在 detectHandlerMethods
方法中完成。
部分代码如下:
如上述代码,解析后的映射对象
- 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
。
以此作为源码入口,对应的处理流程如下图:
通过上图追踪代码,可知进行 URL 匹配的代码入口为 AbstractHandlerMethodMapping
。
具体进行 ULR 匹配的处理逻辑在 AbstractHandlerMethodMapping#lookupHandlerMethod
中,部分代码如下:
通过代码追踪,具体的匹配方法在项目启动时构造的 RequestMappingInfo#getMatchingCondition
中。
具体代码如下:
上述对应了 Spring MVC 不同的匹配规则。
而 API 版本控制的处理,即对 URL 匹配的处理,通过自定义相关的匹配规则即可完成对应的 API 版本 URL 的处理
通过匹配到对应的 RequestMappingInfo
从而从映射关系中获取到 HandlerMethod
,再通过调用 HandlerMethod
标注的资源方法实现资源访问。
二、自定义 URL 匹配实现API版本控制
通过引入自定义匹配规则,实现 API 版本管理 参考方法:
RequestMappingHandlerMapping#getCustomTypeCondition
。 参考方法:RequestMappingHandlerMapping#getCustomMethodCondition
spring-boot-api-version.zip.txt
2.1、项目结构
2.1.1、匹配规则实现 ApiVersionCondition
2.1.2、自定义 HandlerMapping 注册 Condition
关键代码 CustomRequestMappingHandlerMapping
如下: