概述
接口版本控制,比如微服务请求中某个接口需要升级,正常做法是升级我们的版本
比如:localhost:80/api/v1/test
技术实现
我们可以将版本相关的控制以包的形式引入到我们的项目中,那么我们就需要开发我们的对应的版本控制的sdk
1,自定义注解
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiVersion {
/**
* 版本号
* @return
*/
int value() default 1;
}
2,控制开关属性
@RefreshScope
@Data
@ConfigurationProperties(prefix = "api.version")
public class ApiVersionProperties {
boolean enabled;
}
3,重写RequestMapping
public class ApiRequestHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected RequestCondition<ApiVersionCondition> getCustomTypeCondition(Class<?> handlerType) {
ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
return createCondition(apiVersion);
}
@Override
protected RequestCondition<ApiVersionCondition> getCustomMethodCondition(Method method) {
ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
return createCondition(apiVersion);
}
private RequestCondition<ApiVersionCondition> createCondition(ApiVersion apiVersion) {
return apiVersion == null ? null : new ApiVersionCondition(apiVersion.value());
}
}
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
/**
* extract the version part from url. example [v0-9]
*/
private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");
private int apiVersion;
public ApiVersionCondition(int apiVersion) {
this.apiVersion = apiVersion;
}
/**
* // 和另外一个请求匹配条件合并,具体合并逻辑由实现类提供
* @param other
* @return
*/
@Override
public ApiVersionCondition combine(ApiVersionCondition other) {
// latest defined would be take effect, that means, methods definition with
// override the classes definition
return new ApiVersionCondition(other.getApiVersion());
}
/**
* // 检查当前请求匹配条件和指定请求request是否匹配,如果不匹配返回null,
* // 如果匹配,生成一个新的请求匹配条件,该新的请求匹配条件是当前请求匹配条件
* // 针对指定请求request的剪裁。
* // 举个例子来讲,如果当前请求匹配条件是一个路径匹配条件,包含多个路径匹配模板,
* // 并且其中有些模板和指定请求request匹配,那么返回的新建的请求匹配条件将仅仅
* // 包含和指定请求request匹配的那些路径模板。
* @param request
* @return
*/
@Override
public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
if (m.find()) {
Integer version = Integer.valueOf(m.group(1));
// when applying version number bigger than configuration, then it will take
if (version >= this.apiVersion) {
// effect
return this;
}
}
return null;
}
/**
* 针对指定的请求对象request比较两个请求匹配条件。
* 该方法假定被比较的两个请求匹配条件都是针对该请求对象request调用了
* #getMatchingCondition方法得到的,这样才能确保对它们的比较
* 是针对同一个请求对象request,这样的比较才有意义(最终用来确定谁是
* 更匹配的条件)。
* @param other
* @param request
* @return
*/
@Override
public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
// when more than one configured version number passed the match rule, then only
// the biggest one will take effect.
return other.getApiVersion() - this.apiVersion;
}
public int getApiVersion() {
return apiVersion;
}
}
4,注册
@Configuration
@EnableConfigurationProperties(ApiVersionProperties.class)
@ConditionalOnProperty(
value = {"api.version.enabled"},
matchIfMissing = true
)
public class WebConfig implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new ApiRequestHandlerMapping();
}
}
4,最后resource/MATE-INFO/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.springbootgray.apiversion.WebConfig,\
使用
@RestController
@ApiVersion(value = 1)
@RequestMapping("/api/{version}")
调用使用
localhost:8080/api/v1/test