通过自定义@apiversion和@grayrelease注解及扩展springmvc映射机制,可在接口层实现无侵入、不依赖网关的多版本灰度路由,支持版本匹配、灰度分流与全链路透传。

直接用自定义注解 + SpringMVC 请求映射扩展,就能在接口层实现带灰度逻辑的多版本过滤与分发。不侵入业务代码,也不依赖网关或中间件,核心在于让框架自己“看懂”请求该走哪个版本、是否进灰度。
定义可携带业务语义的版本与灰度注解
注解是路由策略的声明入口,必须包含实际路由所需的全部元数据:
-
@ApiVersion 标记方法所属版本(如
"2.0"),支持deprecated = true标识废弃,并附带提示文案,供统一拦截器返回给调用方 -
@GrayRelease 描述灰度规则:可设固定比例(如
ratio = 5表示 5% 流量)、也可指定用户标识前缀(如userGroups = {"admin", "test-"}),后者优先级高于比例 - 两个注解都作用于 METHOD 级别,保留运行时信息(
@Retention(RUNTIME)),确保后续能被反射读取
编写版本感知的请求条件类(ApiVersionRequestCondition)
这是路由精准性的关键。它决定“当前请求是否匹配该方法”:
- 从请求中提取版本标识——支持多种来源:Header(
X-Api-Version)、URL 路径前缀(如/v2/users)、或 Query 参数(?version=2.0),按优先级链式尝试 - 若请求未带版本,默认走最高可用非废弃版本(可配置 fallback 策略)
- 灰度判断在此同步介入:先检查是否命中
userGroups,再按比例哈希(如对用户ID或请求 traceId 做 MD5 取模),避免随机导致状态不一致 - 重写
getMatchingCondition()和compareTo(),确保 Spring 能正确排序多个候选方法(例如 v1.0 与 v2.0 同时匹配时,选更优者)
替换默认映射处理器(ApiVersionRequestMappingHandlerMapping)
让 Spring MVC 在初始化阶段就识别你的版本逻辑:
- 继承
RequestMappingHandlerMapping,重写getCustomTypeCondition()和getCustomMethodCondition() - 对每个
@RequestMapping方法,自动扫描其上的@ApiVersion和@GrayRelease,构造对应的ApiVersionRequestCondition - 注册为
@PrimaryBean,确保 Spring Boot 自动使用它替代默认处理器 - 可额外加入全局版本白名单校验:比如禁止 v0.9 直接调用 v2.0 接口,通过
HandlerMethodArgumentResolver统一注入版本上下文
补充轻量灰度上下文透传(可选但推荐)
当服务间调用涉及 Feign 或 RestTemplate 时,需把当前请求的版本/灰度标记透传下去:
- 利用
RequestContextHolder将版本信息存入ThreadLocal - 为 Feign 配置
RequestInterceptor,自动添加X-Api-Version和X-Gray-Flag: trueHeader - RestTemplate 则通过
ClientHttpRequestInterceptor实现同效透传 - 这样整个调用链路的下游服务也能基于同样规则做版本路由,实现全链路灰度










