我的编程空间,编程开发者的网络收藏夹
学习永远不晚

springboot怎么实现接口灰度发布

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

springboot怎么实现接口灰度发布

这篇文章主要介绍“springboot怎么实现接口灰度发布”,在日常操作中,相信很多人在springboot怎么实现接口灰度发布问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”springboot怎么实现接口灰度发布”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

前言

对灰度发布有所了解的同学应该知道,灰度发布的目的之一,就是能够根据业务规则的调整,交互上呈现不同的形式,举例来说,当前有2个版本,V1.0和V2.0 ,那么可能表现的形式大概有下面几种:

  • V1.0,界面上的交互形态为A,V2.0版本界面上的交互形式为B;

  • 某个交互,针对同一个接口A来说,V1.0,请求接口A,要求的返回值包括5个字段;V2.0,请求接口A,要求返回值包括10个字段;

  • 某个交互,在V1.0和V2.0中,将使用不同的接口;

实际情况可能会更复杂,在微服务广泛使用的今天,一般的思路是,通过一个获取配置的接口,前端拿到所有的参数配置,根据参数配置的不同,具体实现思路如下:

  • 比如V1版本下,某个配置的值为1,这时候使用A交互;如果要使用交互B,只需要更改配置中心这个值为2,则前端就可以将交互切位B;

  • 或者说,交互不变,但是交互的处理逻辑更复杂了,于是原来的接口无法再满足要求,这时候,可以重新提供一个接口,同样通过配置参数的不同来控制;

于是,从后端接口层面来说,一个比较常用也是通用的处理方式是,通过配置接口来达到切换交互,或者说达到灰度发布的目的,灰度发布的核心本质也正在于通过某种方式从一种数据形态切换到另一种形态;

最小化改造方式

上面聊到了通过配置参数接口来达到灰度的目的,事实上,在一些规模较小的项目中,并没有接入分布式配置中心的情况下,可能上面的解决办法并不是一个很好的方式;

举例来说,灰度要达到的目的是,V1.0 的 获取用户列表的接口返回的是本月新增的用户,而V2.0要求返回最近2个月注册的用户,而且接口地址不变,最多就是在参数上面允许适当变更,即做到前端最小化改动;

这个需求,乍然一想,觉得很是不可思议,一个controller类里面,两个同样的接口映射路径肯定不行的啊,比如看下面这个例子,

@RestControllerpublic class UserController {    @Autowired    private UserService userService;    @GetMapping("/list")    public Object getUserLists1(){        return userService.getUserLists1();    }     @GetMapping("/list")    public Object getUserLists2(){        return userService.getUserLists2();    } }

当前请求接口时,直接报错了,这个错误想必大家都能理解吧,我就不过多做解释了

springboot怎么实现接口灰度发布

springmvc接口请求原理

下面贴出一张关于springmvc接口请求原理的流程图,即一个请求最终到达某个具体的controller时经历的一个完整的过程,相信有个SSM开发或者springboot开发经验的同学对这个图应该不陌生;

springboot怎么实现接口灰度发布

从大的分类上,主要包括下面几个核心处理组件:

  • Dispatcher Servlet ,请求分发器,收到请求调用处理器映射器HandlerMapping;

  • HandlerMapping,HandlerAdapter,处理器映射器和处理器适配器,根据请求的url地址,定位到具体的controller中的具体的处理方法;

  • View Resolver,视图解析器 ,解析接口的返回数据并返回具体View给Dispatcher Servlet ;

在上面这几个组件中,需要重点关注这个叫做 HandlerMapping 的组件,为了实现上文谈到的灰度发布功能,就需要好好研究下HandlerMapping的原理;

HandlerMapping简介

HandlerMapping在这个SpringMVC体系结构中有着举足轻重的地位,充当着url和Controller之间映射关系配置的角色,主要有三部分组成:

  • HandlerMapping 映射注册;

  • 根据url获取对应的处理器;

  • 拦截器注册

在springmvc中,其核心类为 RequestMappingHandlerMapping ,该类中的囊括了与请求映射处理相关的所有实现,举例来说,

  • match(HttpServletRequest request, String pattern) ,通过里面的match方法,可以将request中的请求路径与规则路径做匹配;

  • registerHandlerMethod,注册处理器;

springboot怎么实现接口灰度发布

在该类中,我们注意到这样两个如下的方法,但是其方法内部无任何的实现逻辑,对spring源码稍有了解的同学应该知道,这个肯定是spring框架对于该类预留出来的可供开发中扩展的方法,而这两个方法就是用于实现本次需求的两个核心方法;

我们注意到两个方法的返回值均为RequestCondition,即请求条件的对象,从上面了解到HandlerMapping 是在容器初始化执行,那么一定有一个时机,只要客户端重写了HandlerMapping的这两个方法内部的逻辑,就可以通过解析handleType的参数,达到通过某种参数条件,满足本文的最小化前端改造的需求;

springboot怎么实现接口灰度发布

关于RequestCondition几点补充:

  • RequestCondition是Spring MVC对一个请求匹配条件的概念建模;

  • 实现类可能是针对以下情况之一:路径匹配,头部匹配,请求参数匹配,可产生MIME匹配,可消费MIME匹配,请求方法匹配,或者是以上各种情况的匹配条件的一个组合;

RequestCondition接口定义

public interface RequestCondition<T> {    //和另外一个请求匹配条件合并,具体合并逻辑由实现类提供    T combine(T var1);         // 检查当前请求匹配条件和指定请求request是否匹配,如果不匹配返回null,    // 如果匹配,生成一个新的请求匹配条件,该新的请求匹配条件是当前请求匹配条件    // 针对指定请求request的剪裁。    // 举个例子来讲,如果当前请求匹配条件是一个路径匹配条件,包含多个路径匹配模板,    // 并且其中有些模板和指定请求request匹配,那么返回的新建的请求匹配条件将仅仅    // 包含和指定请求request匹配的那些路径模板。    @Nullable    T getMatchingCondition(HttpServletRequest var1);     // 针对指定的请求对象request比较两个请求匹配条件。    // 该方法假定被比较的两个请求匹配条件都是针对该请求对象request调用了    // #getMatchingCondition方法得到的,这样才能确保对它们的比较    // 是针对同一个请求对象request,这样的比较才有意义(最终用来确定谁是    // 更匹配的条件)。    int compareTo(T var1, HttpServletRequest var2);}

由接口源代码可以看出,接口RequestCondition是一个泛型接口。事实上,它的泛型参数T通常也会是一个RequestCondition对象,搞清这一点就能和上面的HandlerMapping中的两个即将要重写的方法就能产生联系了;

代码实现过程

1、添加一个自定义注解用于标注接口类以及接口方法

通过上面的分析,我们了解到可以通过HandlerMapping 中的getCustomTypeCondition方法和getCustomMethodCondition方法,读取到接口类或者接口方法中的元信息,比如接口路径,注解,方法名称等,

怎样才能实现前端的最小化改造呢?主要思路是,通过参数控制的形式,比如前端不用改动原来的接口地址,只需传入不同的参数即可满足要求,于是可以通过自定义注解的形式,给不同的方法添加注解,通过封装注解参数为RequestCondition的方式来实现;

import java.lang.annotation.*; @Documented@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface ApiVersion {     //具体版本号    double value(); }

2、自定义HandleMapping

新增一个类,继承RequestMappingHandlerMapping,重写里面的两个方法,封装成RequestCondition提供后续调用;

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);    }}

3、自定义封装RequestCondition

封装子自定义的RequestCondition逻辑,该类会在客户端请求接口时,根据入参进行一系列的与真正的执行接口进行匹配的逻辑操作,比如,默认情况下,如果请求URL中不传入任何参数,将返回默认的 V1.0的接口;

import org.apache.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;    }}

4、注册自定义的 ApiVersionHandleMapping

import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; public class ApiVersionMappingRegister implements WebMvcRegistrations {     @Override    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {        return new ApiVersionHandleMapping();    }}
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration; @Configurationpublic class BaseConfiguration {     @Bean    public WebMvcRegistrations getWebMvcRegistrations(){        return new ApiVersionMappingRegister();    } }

5、接口测试

对本文开篇的接口做简单的改造,添加自定义注解

import com.congge.configs.ApiVersion;import com.congge.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController; @RestController@ApiVersion(3.0)public class UserController {     @Autowired    private UserService userService;     @GetMapping("/list")    @ApiVersion(1.0)    public Object getUserLists1(){        return userService.getUserLists1();    }     @GetMapping("/list")    @ApiVersion(2.0)    public Object getUserLists2(){        return userService.getUserLists2();    }}

启动项目后,做如下接口测试:

不添加任何参数,默认不加任何参数,将请求V1版本的接口

springboot怎么实现接口灰度发布

接口请求中添加 api-version = 2.0 ,将请求到V2对应的接口

springboot怎么实现接口灰度发布

通过以上的演示,我们基本上实现了一个基于 springboot 实现接口多版本控制的接口灰度发布的功能。

到此,关于“springboot怎么实现接口灰度发布”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

springboot怎么实现接口灰度发布

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

springboot怎么实现接口灰度发布

这篇文章主要介绍“springboot怎么实现接口灰度发布”,在日常操作中,相信很多人在springboot怎么实现接口灰度发布问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”springboot怎么实现接口灰
2023-06-29

SpringCloud如何实现灰度发布

这篇文章主要讲解了“SpringCloud如何实现灰度发布”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringCloud如何实现灰度发布”吧!1.什么是灰度发布?灰度发布又称金丝雀发布
2023-06-30

java灰度发布如何实现

Java灰度发布是指在发布新版本时,只将一部分用户引流到新版本,以验证新版本的稳定性和性能,最终再将全部用户引流到新版本。下面是几种实现Java灰度发布的常见方法:通过配置文件实现:可以在项目中引入一个配置文件,用来控制用户的访问流量。在配
2023-10-27

F5与Openshift集成怎么实现灰度发布

这期内容当中小编将会给大家带来有关F5与Openshift集成怎么实现灰度发布,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、为什么要使用灰度发布什么是灰度发布灰度发布是指在黑与白之间,能够平滑过渡的一
2023-06-04

nginx+lua+redis 灰度发布实现方案

目录第一种方案:第二种方案:背景: 公司要把现有的某传统项目进行微服务化,拆分后要分批次预发布qGWnpqIpfe,实现某部分使用户使用微服务模块,其他用户使用传统项目。待微服务稳定、无bug后全部用户迁移至微服务系统。以上为背景,实现此
nginx+lua+redis 灰度发布实现方案
2024-10-10

Docker与Nginx结合实现网站灰度发布(如何利用Docker和Nginx实现网站的灰度发布?)

利用Docker和Nginx,可实现网站灰度发布。首先构建新旧版本容器镜像。部署旧版本,配置Nginx代理。随后部署新版本,修改Nginx配置路由部分流量。测试新版本,逐步增加流量。当新版本稳定后,完全切换。Docker灰度发布优势包括隔离性、可移植性、可扩展性和自动化。最佳实践包括谨慎监控、明确回滚策略、逐步增加流量和全面测试。
Docker与Nginx结合实现网站灰度发布(如何利用Docker和Nginx实现网站的灰度发布?)
2024-04-02

SpringBoot项目之怎么实现短信发送接口

这篇文章主要讲解了“SpringBoot项目之怎么实现短信发送接口”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot项目之怎么实现短信发送接口”吧!一. 短信接口实现描述:请
2023-06-25

怎么实现Java开发SpringBoot集成接口文档

本篇内容介绍了“怎么实现Java开发SpringBoot集成接口文档”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!swagger vs sm
2023-06-25

JavaAgent如何实现http接口发布

这篇文章主要介绍“JavaAgent如何实现http接口发布”,在日常操作中,相信很多人在JavaAgent如何实现http接口发布问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaAgent如何实现ht
2023-07-05

怎么用SpringBoot实现后端接口

本篇内容介绍了“怎么用SpringBoot实现后端接口”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!所需依赖包这里用的是SpringBoot
2023-06-16

springboot+vue组件开发怎么实现接口断言功能

本篇内容介绍了“springboot+vue组件开发怎么实现接口断言功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!基于 springbo
2023-06-30

springboot批量请求接口怎么实现

在Spring Boot中实现批量请求接口可以通过以下步骤实现:创建一个包含所有待请求的接口URL的列表或数组。使用RestTemplate或者HttpClient等HTTP客户端库发送批量请求。下面以RestTemplate为例,首先在S
2023-10-26

使用Docker Compose、Nginx和MariaDB实现PHP应用程序的灰度发布

灰度发布是一种软件发布的策略,通过在生产环境中逐步引入新版本,来缓解发布带来的风险。在实际应用中,我们可以通过使用Docker Compose来管理容器化的应用程序,结合Nginx负载均衡和MariaDB来实现灰度发布。Docker Com
2023-10-21

JavaAgent实现http接口发布方式浅析

这篇文章主要介绍了JavaAgent实现http接口发布方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2023-03-02

SpringBoot项目中怎么实现接口防刷

SpringBoot项目中怎么实现接口防刷,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、自定义注解import java.lang.annotation.Retention
2023-06-20

springboot怎么利用aop实现接口异步

小编给大家分享一下springboot怎么利用aop实现接口异步,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、前言在项目中发现有接口(excel导入数据)处理数据需要耗时比较长的时间,是因为数据量比较大,同时数据的校验
2023-06-22

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录