Spring擴展之基于HandlerMapping實現(xiàn)接口灰度發(fā)布實例
背景
面試經(jīng)常被問到,你了解spring源碼嗎?有基于spring做過什么擴展嗎?
除了PropertyPlaceholderConfigurer處理占位符(被說爛了)還有其他的嗎?
看了springmvc的源碼,有了一個新的案例可講(吹)
基于HandlerMapping實現(xiàn)接口灰度發(fā)布
說這個之前可以先鋪墊一下,將故事講的生動一點,我們來簡單模擬一下。
面試官:“簡歷上說你對spring源碼比較熟悉,能簡單講講你對ioc、aop的理解嗎?”
張三:“ioc是……aop是……巴拉巴拉”
(背了一大段八股文,毫無新意,面試官面無表情,然后打斷張三,繼續(xù)問)
面試官:你說對spring源碼很熟悉,有多熟悉,在實際開發(fā)中有用過?擴展過嗎?
張三:“有過呀,當(dāng)時有個系統(tǒng),升級改動比較大,對于同一批接口,老用戶和新用戶返回的數(shù)據(jù)不一樣,為了實現(xiàn)系統(tǒng)的最小化改動,我當(dāng)時就用spring的HandlerMapping解決了這個問題,前端訪問的接口不變,只在參數(shù)中加一個接口版本號,就能實現(xiàn)灰度……,具體實現(xiàn)是這樣的”
實現(xiàn)方案
自定義注解
新增一個自定義注解,用來標注接口的適配的版本號,默認為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); } }
實現(xiàn)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"; } }
到此這篇關(guān)于Spring擴展之基于HandlerMapping實現(xiàn)接口灰度發(fā)布實例的文章就介紹到這了,更多相關(guān)基于HandlerMapping實現(xiàn)接口灰度發(fā)布內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springBoot 項目排除數(shù)據(jù)庫啟動方式
這篇文章主要介紹了springBoot 項目排除數(shù)據(jù)庫啟動方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09阿里規(guī)范:為何boolean類型變量命名禁用is開頭
這篇文章主要給大家介紹了關(guān)于阿里規(guī)范:為何boolean類型變量命名禁用is開頭的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08Springboot自動裝配之注入DispatcherServlet的實現(xiàn)方法
這篇文章主要介紹了Springboot自動裝配之注入DispatcherServlet,Springboot向外界提供web服務(wù),底層依賴了springframework中的web模塊來實現(xiàn),那么springboot在什么時機向容器注入DispatcherServlet這個核心類的呢?帶著這個問題一起通過本文學(xué)習(xí)吧2022-05-05java中申請不定長度數(shù)組ArrayList的方法
今天小編就為大家分享一篇java中申請不定長度數(shù)組ArrayList的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07Java基礎(chǔ)知識精通二維數(shù)組的應(yīng)用
為了方便組織各種信息,計算機常將信息以表的形式進行組織,然后再以行和列的形式呈現(xiàn)出來。二維數(shù)組的結(jié)構(gòu)決定了其能非常方便地表示計算機中的表,以第一個下標表示元素所在的行,第二個下標表示元素所在的列。下面簡單了解一下二維數(shù)組,包括數(shù)組的聲明和初始化2022-04-04