Spring扩展之基于HandlerMapping实现接口灰度发布实例

 更新时间:2023年08月31日 08:32:39   作者:轻尘×  
这篇文章主要介绍了Spring扩展之基于HandlerMapping实现接口灰度发布实例,灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式,灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度,需要的朋友可以参考下

背景

面试经常被问到,你了解spring源码吗?有基于spring做过什么扩展吗?

除了PropertyPlaceholderConfigurer处理占位符(被说烂了)还有其他的吗?

看了springmvc的源码,有了一个新的案例可讲(吹)

基于HandlerMapping实现接口灰度发布

说这个之前可以先铺垫一下,将故事讲的生动一点,我们来简单模拟一下。

面试官:“简历上说你对spring源码比较熟悉,能简单讲讲你对ioc、aop的理解吗?”

张三:“ioc是……aop是……巴拉巴拉”

(背了一大段八股文,毫无新意,面试官面无表情,然后打断张三,继续问)

面试官:你说对spring源码很熟悉,有多熟悉,在实际开发中有用过?扩展过吗?

张三:“有过呀,当时有个系统,升级改动比较大,对于同一批接口,老用户和新用户返回的数据不一样,为了实现系统的最小化改动,我当时就用spring的HandlerMapping解决了这个问题,前端访问的接口不变,只在参数中加一个接口版本号,就能实现灰度……,具体实现是这样的”

实现方案

自定义注解

新增一个自定义注解,用来标注接口的适配的版本号,默认为1.0版本

package com.fast.alibaba.annotation;
import java.lang.annotation.*;
/**
 * 自定义版本号注解
 */
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiVersion {
    double value() default 1.0;
}
 

自定义HandleMapping

自定义HandleMapping,继承spring家的HandleMapping,并重写两个getCustomTypeCondition方法

package com.fast.alibaba.handlemapping;
import com.fast.alibaba.annotation.ApiVersion;
import com.fast.alibaba.condition.ApiVersionRequestCondition;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
public class ApiVersionHandleMapping extends RequestMappingHandlerMapping {
    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = AnnotationUtils.getAnnotation(handlerType, ApiVersion.class);
        return new ApiVersionRequestCondition(apiVersion != null ? apiVersion.value() : 1.0);
    }
    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = AnnotationUtils.getAnnotation(method, ApiVersion.class);
        if(apiVersion == null){
            apiVersion = AnnotationUtils.getAnnotation(method.getDeclaringClass(), ApiVersion.class);
        }
        return new ApiVersionRequestCondition(apiVersion != null ? apiVersion.value() : 1.0);
    }
}

实现RequestCondition接口

以便识别前端传送的版本与接口上注解版本匹配

package com.fast.alibaba.condition;
import com.alibaba.cloud.commons.lang.StringUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import javax.servlet.http.HttpServletRequest;
public class ApiVersionRequestCondition implements RequestCondition<ApiVersionRequestCondition> {
    private double apiVersion = 1.0;
    private static final String VERSION_NAME = "api-version";
    public double getApiVersion() {
        return apiVersion;
    }
    public ApiVersionRequestCondition(double apiVersion){
        this.apiVersion=apiVersion;
    }
    @Override
    public ApiVersionRequestCondition combine(ApiVersionRequestCondition method) {
        return method;
    }
    @Override
    public int compareTo(ApiVersionRequestCondition other, HttpServletRequest request) {
        return Double.compare(other.getApiVersion(),this.getApiVersion());
    }
    @Override
    public ApiVersionRequestCondition getMatchingCondition(HttpServletRequest request) {
        double reqVersionDouble = 1.0;
        String reqVersion = request.getHeader(VERSION_NAME);
        if(StringUtils.isEmpty(reqVersion)){
            reqVersion = request.getParameter(VERSION_NAME);
        }
        if(!StringUtils.isEmpty(reqVersion)){
            reqVersionDouble = Double.parseDouble(reqVersion);
        }
        if(this.getApiVersion() == reqVersionDouble){
            return this;
        }
        return null;
    }
}

自定义WebMvcRegistrations

package com.fast.alibaba.register;
import com.fast.alibaba.handlemapping.ApiVersionHandleMapping;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
 * 注册自定义的 ApiVersionHandleMapping
 */
public class ApiVersionMappingRegister implements WebMvcRegistrations {
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new ApiVersionHandleMapping();
    }
}

注入WebMvcRegistrations

package com.fast.alibaba.config;
import com.fast.alibaba.register.ApiVersionMappingRegister;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BaseConfiguration {
    @Bean
    public WebMvcRegistrations getWebMvcRegistrations(){
        return new ApiVersionMappingRegister();
    }
}

测试类

package com.fast.alibaba.controller;
import com.fast.alibaba.annotation.ApiVersion;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestHandlerMappingController {
    @GetMapping("/getInfo")
    @ApiVersion(1.0)
    public String getSomeInfoByV1(){
        return "version 1.0";
    }
    @GetMapping("/getInfo")
    @ApiVersion(2.0)
    public String getSomeInfoByV2(){
        return "version 2.0";
    }
    @GetMapping("/getInfo")
    @ApiVersion(3.0)
    public String getSomeInfoByV3(){
        return "version 3.0";
    }
}

到此这篇关于Spring扩展之基于HandlerMapping实现接口灰度发布实例的文章就介绍到这了,更多相关基于HandlerMapping实现接口灰度发布内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springBoot 项目排除数据库启动方式

    springBoot 项目排除数据库启动方式

    这篇文章主要介绍了springBoot 项目排除数据库启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Spring MVC请求参数的深入解析

    Spring MVC请求参数的深入解析

    这篇文章主要给大家介绍了关于Spring MVC请求参数解析的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • 阿里规范:为何boolean类型变量命名禁用is开头

    阿里规范:为何boolean类型变量命名禁用is开头

    这篇文章主要给大家介绍了关于阿里规范:为何boolean类型变量命名禁用is开头的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Springboot自动装配之注入DispatcherServlet的实现方法

    Springboot自动装配之注入DispatcherServlet的实现方法

    这篇文章主要介绍了Springboot自动装配之注入DispatcherServlet,Springboot向外界提供web服务,底层依赖了springframework中的web模块来实现,那么springboot在什么时机向容器注入DispatcherServlet这个核心类的呢?带着这个问题一起通过本文学习吧
    2022-05-05
  • SpringBoot Mail邮件任务详情

    SpringBoot Mail邮件任务详情

    这篇文章主要介绍了SpringBoot Mail邮件任务详情,文章通过spring-boot-starter-mail包展开详细内容,需要的小伙伴可以参考一下
    2022-05-05
  • 浅谈MyBatis中@MapKey的妙用

    浅谈MyBatis中@MapKey的妙用

    这篇文章主要介绍了MyBatis中@MapKey的妙用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • java中申请不定长度数组ArrayList的方法

    java中申请不定长度数组ArrayList的方法

    今天小编就为大家分享一篇java中申请不定长度数组ArrayList的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • java开发中常遇到的各种难点以及解决思路方案

    java开发中常遇到的各种难点以及解决思路方案

    Java项目是一个复杂的软件开发过程,其中会涉及到很多技术难点,这篇文章主要给大家介绍了关于java开发中常遇到的各种难点以及解决思路方案的相关资料,需要的朋友可以参考下
    2023-07-07
  • Java基础知识精通二维数组的应用

    Java基础知识精通二维数组的应用

    为了方便组织各种信息,计算机常将信息以表的形式进行组织,然后再以行和列的形式呈现出来。二维数组的结构决定了其能非常方便地表示计算机中的表,以第一个下标表示元素所在的行,第二个下标表示元素所在的列。下面简单了解一下二维数组,包括数组的声明和初始化
    2022-04-04
  • lombok 子类中如何使用@Builder问题

    lombok 子类中如何使用@Builder问题

    这篇文章主要介绍了lombok 子类中如何使用@Builder问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09

最新评论