基于CustomCondition实现spring mvc的版本号路由插件

本文介绍了如何使用CustomCondition实现Spring MVC的版本号路由插件,允许不同版本的接口在同一URL下通过请求头进行路由和隔离。支持快速接入,可自定义版本号规则,并详细阐述了实现过程和核心逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于CustomCondition实现spring mvc的版本号路由插件

需求

先描述下我实现的个人需求, 项目中有对接客户端, 客户端的版本号是多样且并存的.
有些时候提供给客户端的某个接口, 在不同的版本号下逻辑不同, 且不能做成兼容. 需要不同版本的接口并存. 此时一般方案可能需要修改url地址, 开一个新接口给新版本.
所以这里期望有一种办法可以使不同版本的接口并存在同一个url下, 只通过 header请求头来实现路由和隔离.

提出以下几点效果预设

  1. 支持快速接入
  2. 针对不同项目中的版本号规则能自主切换, 支持扩展
  3. 不影响不需要版本控制的接口(有些接口所有版本客户端都一致那种)

实现后效果

快速接入

  1. 导入依赖(没上传官方仓库, 只能通过down源码先打包到本地或者私有仓库之类的)
  2. 在springBoot启动类上加注解 @EnableWebVersionControl
  3. (可选)在application.yml/application.xml中配置参数,
    提供了两个参数
    webmvc.version.mapping.header-key
    表示请求中的版本号字段放在哪个key里, 默认值为version
    webmvc.version.mapping.clazz
    表示启用的版本判断逻辑是什么, 目前提供了两种判断, 一种是int型, IntegerVersionRequestCondition
    另一种是String型, StringVersionRequestCondition, 默认是型
    int型和string型的区别:
    int型对 数字编号类型的版本号生效
    string型对 形如 2.1.2 类型的版本号生效, 不限制.的位数
  4. 对需要版本号控制的接口替换注释 @PostMappingWithVersion(目前只对POST做了支持), 在minVersion, maxVersion属性上加上版本号上下限, 可选加order排序, 数字越小优先级越高
  5. 客户端请求接口测试, 通过请求头实现路由, 若版本号不在匹配规则里, 则会返回404.版本号规则左右都为闭区间

效果

  1. 不影响不加控制的接口
  2. 加控制的接口支持版本号匹配
  3. 某个请求匹配到多个适配的接口时, 支持通过order参数排序, 数字越小优先级越高, 注: 排序只在除版本号外的属性完全相同的情况下才生效

实现方案

大概的流程思路如下:

  1. 先写一个自己的注解, 类似@RequestMapping这种, 让版本规则能作为参数写入注解
  2. 通过spring mvc代码中预留的customCondition实现版本号匹配和校验规则, 主要是实现getMatchingCondition和compareTo方法, 为了便于扩展, 这里实现一个抽象层的版本号控制器. 具体的匹配规则和校验等规则预留接口供子类实现.
  3. 通过实现RequestMappingHandlerMapping中的getCustomMethodCondition方法, 将实现好的CustomCondition注入到HandlerMapping., 为了便于扩展, 具体注入哪种类型的customCondition支持动态扩展. 通过获取class的方式反射注入.
  4. 通过WebMvcRegistrations注入自实现的RequestMappingHandlerMapping,
  5. 通过@Import编写注解开关类实现类似@EnableXxx功能的注解
  6. 编写一个抽象的VersionRequestCondition类, 支持扩展和切换version匹配规则.

源码

代码比较多, 直接上传github了
https://github.com/sunwenjieIT/spring-boot-webmvc-version-mapping
后面讲下比较核心的几个点

重要逻辑点

  1. 怎么避免相同的url在注入容器时不报错?
    其实只需要实现RequestCondition接口, 把版本号信息放入

正常情况下 两个完全相同的url(所有的其他http参数都一致, 如是否post/get, 对应的请求头等等), 在启动时就会报错, 提示你重复了. 这个重复的校验是在注入过程中校验的.
AbstractHandlerMethodMapping.MappingRegistry.assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping)
这个方法负责实际的校验工作. 做两件事.
1. 先查注册的url是否有之前已经注册的HandlerMethod
2. 如果发现之前已经注册了一个HandlerMethod, 那比对一下两者是否一致.
3. 步骤2中结果若比对一致, 报错, 提示mapping重复注册.
有两个部分的代码要重点看
第一个是T的这个mapping, 作为map的key, 他的hash方法是被重写过的. T的类型根据接口的种类来区分, 种类说的是接入的方式, 比如xml配置的, 从@Controller来的等等, 通常接口通过@Controller来的则T类型为 RequestMappingInfo. 他的hash被重写成了如下形式

	@Override
	public int hashCode() {
   
		return (this.patternsCondition.hashCode() * 31 +  // primary differentiation
				this<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值