spring扩展之基于HandlerMapping实现接口灰度发布的demo

news2025/1/19 20:22:01

背景

面试经常被问到,你了解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";
    }

}

 

 

 

面试官:“还算有点东西,你回去等通知吧”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/106168.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

运营活动没做好,是没有明确目标

有很多运营人在做项目的时候&#xff0c;其实没有一个明确的目标&#xff0c;不清楚自己究竟为什么要做这件事。 我们在做运营方案前&#xff0c;要分析用户的需求有哪些&#xff0c;如何达成目标&#xff0c;制定出一个计划&#xff1a; 1、要做什么——计划 我们需要掌握运…

ES基础入门

ES 一、简介 1、Elastic Stack ES技术栈&#xff1a; ElasticSearch&#xff1a;存数据搜索&#xff1b;QL&#xff1b;Kibana&#xff1a;Web可视化平台&#xff0c;分析。LogStash&#xff1a;日志收集&#xff0c;Log4j:产生日志&#xff1b;log.info(xxx)。。。。 使用…

软件测试面试题和面试流程

自我介绍部分 .... 项目经历 .... 技能部分 性能 使用什么工具&#xff1f;介绍下最近做的性能测试项目&#xff0c;性能测试过程中遇到哪些问题&#xff1f;性能标准谁来定&#xff1f;你们性能测试的流程是什么&#xff1f;什么是分布式&#xff1f;为什么要用分布式&a…

硅片检测半导体运动台控制器的设计(二)

虽然我国目前对于精密硅片检测运动平台的整机研发还比较空白&#xff0c;但是值得注意的是&#xff0c;对于 X、Y 两自由度运动平台&#xff0c;甚至多自由度运动平台、先进驱动方式和控制策略的研究已经积累了一定的经验&#xff0c;吸收这些经验并应用于本运动平台的研发对选…

分布式系统(事务处理)

文章目录事务&#xff08;Transaction&#xff09;分布式事务原子提交协议单阶段提交两阶段提交三阶段提交串行等价 / 并发控制分布式死锁锁超时全局等待图边追逐算法事务放弃时的恢复服务器崩溃后的恢复恢复文件重组恢复文件日志从Crash 中恢复2PC 的恢复事务&#xff08;Tran…

【Bio】基础生物学 - 化学键 chemical bond

文章目录化学键1. 共价键2. 离子键3. 金属键4. 非共价键5. 氢键Ref.化学键 化学键&#xff08;chemical bond&#xff09;是纯净物分子内或晶体内相邻两个或多个原子&#xff08;或离子&#xff09;间强烈的相互作用力的统称。使离子&#xff08;ion&#xff09;相结合或原子&…

【强化学习笔记】二.价值学习

文章目录Q&A1.DQN工作原理2.如何训练DQN2.1.如何更新模型参数3.2.1.完整走完流程&#xff0c;再更新模型参数。3.2.2.无需走完流程&#xff0c;即可更新模型参数。3.如何将TD算法应用到DQN网络Q&A 问&#xff1a;强化学习的目标是什么&#xff1f; 最大化累计奖励&am…

Windows 的 常用指令操作

目录 1、启动方式 2、修改cmd窗口背景色和字体色 3、文件夹常用指令 4、网络相关常用指令 5、其他常用命令 1、启动方式 用户启动&#xff1a;winR&#xff0c;输入cmd&#xff0c;Enter。 管理员启动&#xff1a;winR&#xff0c;输入cmd&#xff0c;CTRLShiftEnter。 …

Dubbo架构设计与源码解析(二) 服务注册

一、Dubbo简介 &#xfeff;Dubbo是一款典型的高扩展、高性能、高可用的RPC微服务框架&#xff0c;用于解决微服务架构下的服务治理与通信问题。其核心模块包含【RPC通信】和【服务治理】&#xff0c;其中服务治理又分为服务注册与发现、服务容错、负载均衡、流量调度等。今天…

强化学习 —— DQN 代码遇到的问题总结

No module named ‘torch‘ 在把 DQN 代码复制到 PyCharm&#xff0c;点击“运行”后&#xff0c;出现了该报错。是因为当前环境中缺少 pytorch。解决方法&#xff1a; pip install torch如果因为网络问题安装特别慢&#xff0c;可从如下源进行下载&#xff1a; pip install…

php宝塔搭建部署实战开源版OneNav网址导航书签系统源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套php开发的开源版OneNav网址导航书签系统源码&#xff0c;感兴趣的朋友可以自行下载学习。 技术架构 PHP7.2 nginx SQLite3 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码&a…

【RuoYi-Vue-Plus】学习笔记 46 - Redisson(十二)布隆过滤器 BloomFilter 简单分析

文章目录前言参考目录测试方法配置说明Demo 方法功能调用流程分析1、布隆过滤器的初始化 tryInit1.1、创建布隆过滤器1.2、初始化布隆过滤器1.2.1、计算 bit 位数1.2.2、计算 Hash 函数个数1.2.3、保存过滤器配置Redis 实际执行结果2、将待比较元素存入布隆过滤器 addRedis 实际…

QT QMenuBra QMenu QAction 菜单栏 操作详解

本文详细的介绍了QMenuBra QMenu QAction 菜单栏的各种操作&#xff0c;例如操作&#xff1a;新建界面、加入菜单项、加入子菜单、新建二级子菜单、QAction分隔符、pMenuBar、点击信号、触发信号、设置图标、设置禁用、设置提示语 等操作 本文作者原创&#xff0c;未经允许禁止…

Eclipse常用设置

Eclipse 是著名的跨平台的自由集成开发环境&#xff08;IDE&#xff09;。最初主要用来 Java 语言开发&#xff0c;但是目前亦有人通过插件使其作为其他计算机语言比如 C 和 Python 的开发工具 目录 1.解决中文乱码设置propertiew编码 2.更改字体大小 3.设置护眼颜色 4.修…

Usaco Training刷怪旅 第二层第一题:Milking Cows

usaco training 关注我持续更新usaco training内容 Three farmers rise at 5 am each morning and head for the barn to milk three cows. The first farmer begins milking his cow at time 300 (measured in seconds after 5 am) and ends at time 1000. The second farmer …

Go语言入门【09】结构体

结构体 相比于Java&#xff0c;在Go语言中没有类的概念&#xff0c;但是多了结构体。结构体与Java中的类很像&#xff0c;是表示一系列同一类型或不同类型的数据构成的数据集合。 例如可以将学生抽象成一个结构体&#xff0c;每一个学生有以下属性&#xff1a; Name&#xf…

基于pytorch搭建CNN 对人像是否戴口罩进行检测分类 详细教程

项目介绍 我们将使用 CNN (卷积神经网络)和机器学习分类器创建一个检测一个人是否戴着口罩的分类器。它将检测一个人是否戴着口罩。 我们将从头开始学习,我将对每一步进行解释。我需要你对机器学习和数据科学有基本的了解。我已经在本地 Windows 10 机器上实现了它,如果你…

A-Level/IB/AP不同课程体系分数可以相互转换吗?

都知道国际学校有不同的课程体系&#xff0c;也会有不同的考试体系。比如A-Level、IB、SAT/ACT和AP&#xff1b;甚至还有国内的高考体系。所以可能有同学家长会问&#xff0c;不同体系之间的分数是否能够进行对比呢&#xff1f; 严格来讲&#xff0c;其实不好对比&#xff0c;但…

wy的leetcode刷题记录_Day59

wy的leetcode刷题记录_Day59 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2022-12-9 前言 目录wy的leetcode刷题记录_Day59声明前言1780. 判断一个数字是否可以表示成三的幂的和题目介绍思路代码收获63. 题目题目介绍思路代码收获178…

m基于RFID和DBSCAN聚类的InSAR室内三维定位算法的matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 许多室内应用需要有关物体的空间信息。示例应用程序包括项目查找&#xff0c;对象级别映射和在仓库或库中管理的大型对象。然而&#xff0c;使用802.11&#xff0c;可见光或声学的基于位置的服务…