java注解本身不实现api版本控制,需结合spring mvc等框架及自定义逻辑:通过@apiversion注解标记版本,再经自定义requestmappinghandlermapping在请求匹配时校验版本兼容性。

Java 中注解本身不直接实现 API 版本控制,它只是声明元数据的机制;真正的版本控制逻辑需要结合框架(如 Spring MVC)和自定义处理逻辑来完成。核心思路是:用自定义注解标记接口版本,再通过拦截器、HandlerMethodArgumentResolver、或者 RequestMappingHandlerMapping 的扩展,在请求匹配阶段根据请求头、路径或参数提取版本信息,并筛选出匹配的控制器方法。
定义版本注解
创建一个用于标记 Controller 方法支持版本范围的注解:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiVersion {
String value() default "1.0"; // 主版本号,如 "1.0"、"2.0"
String[] supported() default {}; // 可选:显式声明支持的多个版本
}
这个注解可加在类或方法上,比如:
@RestController
@RequestMapping("/api/users")
@ApiVersion("1.0")
public class UserControllerV1 {
@GetMapping
@ApiVersion("1.0")
public List<user> list() { ... }
}
@RestController
@RequestMapping("/api/users")
@ApiVersion("2.0")
public class UserControllerV2 {
@GetMapping
@ApiVersion("2.0")
public Page<user> list(@RequestParam int page) { ... }
}</user></user>
从请求中提取版本信息
常见方式有三种,需统一约定并提前确定策略:
-
请求头方式:如
Accept: application/vnd.myapp.v2+json或自定义头X-API-Version: 2.0 -
路径前缀方式:如
/v2/api/users,配合@RequestMapping("/v2/api") -
查询参数方式:如
/api/users?version=2.0(不推荐用于生产,影响缓存和语义)
建议优先使用请求头或路径前缀,更符合 REST 规范。
自定义 RequestMappingHandlerMapping 实现匹配逻辑
重写 getMatchingMapping() 方法,在匹配候选方法时,检查其 @ApiVersion 注解与当前请求的版本是否兼容:
public class VersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
RequestMappingInfo matchingInfo = super.getMatchingMapping(info, request);
if (matchingInfo == null) return null;
String requestVersion = extractVersionFromRequest(request); // 自定义提取逻辑
Method method = info.getHandlerMethod().getMethod();
ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
if (apiVersion == null) apiVersion = AnnotationUtils.findAnnotation(
method.getDeclaringClass(), ApiVersion.class);
if (apiVersion != null && !isVersionMatched(requestVersion, apiVersion)) {
return null; // 版本不匹配,跳过该方法
}
return matchingInfo;
}
private boolean isVersionMatched(String reqVer, ApiVersion ann) {
if (reqVer == null) return false;
String annVer = ann.value();
// 支持简单语义匹配,如 "2.0" == "2.0",或按主版本号匹配 "2.*"
return reqVer.equals(annVer) || reqVer.startsWith(annVer.split("\.")[0] + ".");
}
}
然后在配置类中注册该 Bean 替换默认的 HandlerMapping:
@Bean
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
VersionRequestMappingHandlerMapping mapping = new VersionRequestMappingHandlerMapping();
mapping.setOrder(0);
return mapping;
}
补充:配合 Spring Profiles 或包扫描做隔离(可选)
对差异较大的版本,也可结合 Spring Profile 分离实现:
- 不同版本 Controller 放在不同 package 下,如
com.example.api.v1和com.example.api.v2 - 启动时通过
@Profile("v1")控制组件加载 - 配合
@ComponentScan按 profile 过滤包路径
这种方式适合大版本重构,但不如注解方式灵活轻量;两者可组合使用:注解控制细粒度方法级版本,Profile 控制模块级生命周期。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











