欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springMVC在restful風格的性能優(yōu)化方案

 更新時間:2021年08月23日 10:25:58   作者:shjhhc  
這篇文章主要介紹了springMVC在restful風格的性能優(yōu)化方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

springMVC在restful風格的性能優(yōu)化

目前,restful的接口風格很流行,使用springMVC來搭配restful也是相得益彰。如下,使用@PathVariable注解便可以獲取URL上的值。

@RequestMapping(value = "restful/{name}", method = RequestMethod.GET)
    public String restful(@PathVariable String name){
        return name;
    }

不過如果你認真的研究過springMVC就會發(fā)現(xiàn),restful風格的接口的性能會大大低于正常形式的springMVC接口。比如下面這種方式。

@RequestMapping(value = "norestful", method = RequestMethod.GET)
    public String norestful(@RequestParam String name){
        return name;
    }

測試

為了看到效果,我先進行了測試,工具是Apache-Jmeter

測試參數,并發(fā)量50,總量10000次。

1、非restful接口

這里寫圖片描述

2、restful接口

這里寫圖片描述

對比很明顯,非restful接口的性能是restful接口的1.5倍左右,而且restful接口隨著@Requestmapping接口數量的增多會越來越慢,而非restful接口不會。

不止如此,非restful接口的最大響應時間是67ms,而restful接口的最大響應時間達到了381ms,這在極端情況下很可能會造成請求超時。

匹配原理

先講一下springMVC的路徑匹配邏輯吧。springMVC的請求主要在DispatcherServlet中處理,而請求分發(fā)規(guī)則則在doDispatch()方法中完成。

最后處理邏輯在AbstractHandlerMethodMapping類的lookupHandlerMethod方法中進行。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<Match>();
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); 
        if (directPathMatches != null) {
            addMatchingMappings(directPathMatches, matches, request);
        }
        if (matches.isEmpty()) {
            // No choice but to go through all mappings...
            addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
        }

這段代碼中匹配邏輯有三:

1、List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

這個方法是非常直觀的根據URL來獲取,springMVC會在初始化的時候建立URL和相應RequestMappingInfo的映射。如果不是restful接口,這里就可以直接獲取到了。

2、如果1中已經獲取到,則調用方法addMatchingMappings(directPathMatches, matches, request)進行匹配校驗。

3、如果1中未獲取到匹配方法信息,則調用方法addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);進行全局(all mappings)掃描匹配(this.mappingRegistry.getMappings().keySet())。且會把所有的RequestMappingInfo都遍歷完才會停止,也就是說項目中的@RequestMapping方法越多,這個匹配的效率就越低,性能越差。

在遍歷過程中,SpringMVC首先會根據@RequestMapping中的headers, params, produces, consumes, methods與實際的HttpServletRequest中的信息對比,剔除掉一些明顯不合格的RequestMapping。

如果以上信息都能夠匹配上,那么SpringMVC會對RequestMapping中的path進行正則匹配,剔除不合格的。

接下來會對所有留下來的候選@RequestMapping進行評分并排序。最后選擇分數最高的那個作為結果。

評分的優(yōu)先級為:

path pattern > params > headers > consumes > produces > methods

綜上所述,當使用非restful接口時就會直接獲取對應的HandlerMethod來處理請求,但使用restful接口時,就會每次遍歷所有的方法來查找,性能差由此形成。

優(yōu)化方案

原理:

1、在每個@RequestMapping中添加接口對應服務名的信息。

2、實現(xiàn)自己定義的HandlerMethod查詢邏輯,在HandlerMethod注冊時記錄與之對應的服務名,在查詢時通過HTTP請求頭中的服務名查表獲得HandlerMethod。

實現(xiàn):

每次請求都執(zhí)行這段復雜的匹配邏輯是不可取的。我們要做的就是找辦法繞開它。spring是一個符合開閉原則的框架。對擴展開放,對修改關閉。它提供了很多擴展性給我們。

springmvc中,AbstractHandlerMethodMapping.MappingRegistry里提供了@Requestmapping中name屬性和HandlerMethod的映射如下

private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();

我們剛好可以使用它。

另外,我們看到實現(xiàn)匹配邏輯的方法HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);其本身是個protected方法,

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception

由此便可以在子類中擴展它。

代碼:

我使用基于java config的注解配置.

1、繼承WebMvcConfigurationSupport類,復寫createRequestMappingHandlerMapping方法返回自定義的RequestMappingHandlerMapping類。

 @Override
    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
        return new RestfulRequestMappingHandlerMapping();
    }

2、繼承RequestMappingHandlerMapping類

2.1重寫lookupHandlerMethod方法,完成自己的查找邏輯。

@Override
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    //自己的查找邏輯,如果找不到,再執(zhí)行原有的邏輯,以免出現(xiàn)錯誤情況
        HandlerMethod handlerMethod = lookupHandlerMethodHere(lookupPath, request);
        if (handlerMethod == null)
            handlerMethod = super.lookupHandlerMethod(lookupPath, request);
        return handlerMethod;
    }
//自己的查找邏輯,根據從請求頭中獲取服務名servicename,進行匹配查找
private HandlerMethod lookupHandlerMethodHere(String lookupPath, HttpServletRequest request) {
        String servicename = request.getHeader("servicename");
        if (!StringUtils.isEmpty(servicename)) {
            List<HandlerMethod> methodList = this.getHandlerMethodsForMappingName(servicename);
            if (methodList.size() > 0){
                HandlerMethod handlerMethod = methodList.get(0);
                RequestMappingInfo requestMappingInfo = mappingLookup.get(handlerMethod);
                handleMatch(requestMappingInfo, lookupPath, request);
                return handlerMethod;
            }
        }
        return null;
    }

2.2因為RESTful接口存在@PathVariable,我們還需要調用handleMatch方法來將HTTP請求的path解析成參數。然而這個方法需要的參數是RequestMappingInfo,并不是HandlerMethod,SpringMVC也沒有提供任何映射。

做法:重寫registerHandlerMethod方法,再初始化的時候構建一個從HandlerMethod—>RequestMappingInfo的反向映射。

//映射map
private final Map<HandlerMethod, RequestMappingInfo> mappingLookup = new LinkedHashMap<HandlerMethod, RequestMappingInfo>();
@Override
    protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        mappingLookup.put(handlerMethod, mapping);
        super.registerHandlerMethod(handler, method, mapping);
    }

由此,springMVC優(yōu)化邏輯編寫完成??创a量很少,但想通過自己寫出來,需要對springMVC有相當了解,深入理解springMVC的可擴展點。

最終測試

看下優(yōu)化過后的restful接口

這里寫圖片描述

吞吐量和非restful接口差不多,各項應能都接近,達到預期效果。

spring restful使用中遇到的一個性能問題

在使用spring restful開發(fā)過程中遇到個棘手的問題,解決后來做個備注。希望其他遇到相同問題的朋友可以參考下。

客戶端訪問rest api速度過慢,每次請求超過1秒鐘

原因:

返回類型是強類型,SPRING將其序列化為json對象消耗時間過長。

解決方案:

返回類型改為String,改動很小,只需要將原來的強類型對象通過fastjson的JSON.toJSONString方法進行轉換即可;

@RequestMapping加參數produces = { "application/json;charset=UTF-8" }

通過以上修改,原先1秒鐘左右的請求變?yōu)?0-50毫秒。雖然解決,但是否是spring本身問題還是配置問題,抑或代碼寫法問題,還未深究,暫時先趕項目進度,項目完成后再回頭查找具體原因。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • SpringCloud項目中集成Sentinel問題

    SpringCloud項目中集成Sentinel問題

    在SpringCloud項目中集成Sentinel,可以實現(xiàn)流量控制、熔斷降級等功能,提升系統(tǒng)穩(wěn)定性和可用性,集成步驟包括添加Sentinel依賴、配置控制臺地址、啟動控制臺、配置限流熔斷規(guī)則、使用注解和集成SpringCloudGateway,這有助于處理高并發(fā)場景,保護服務穩(wěn)定運行
    2024-10-10
  • Java BigDecimal使用方法詳解

    Java BigDecimal使用方法詳解

    Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數進行精確的運算。雙精度浮點型變量double可以處理16位有效數,但在實際應用中,可能需要對更大或者更小的數進行運算和處理
    2022-12-12
  • Java easyexcel導出報內存溢出的問題解決

    Java easyexcel導出報內存溢出的問題解決

    在Java開發(fā)時,使用EasyExcel處理大數據量導出可能遇到內存溢出問題,本文深入分析了內存溢出的原因,并提出了優(yōu)化策略,感興趣的可以了解一下
    2024-10-10
  • Java Random.nextInt()方法原理解析

    Java Random.nextInt()方法原理解析

    這篇文章主要介紹了Java Random.nextInt()方法原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09
  • hibernate中的對象關系映射

    hibernate中的對象關系映射

    hibernate中的ORM映射文件通常以.hbm.xml作為后綴。使用這個映射文件不僅易讀,而且可以手工修改,也可以通過一些工具來生成映射文檔,下文給大家詳細的介紹hibernate中的對象關系映射,需要的朋友參考下吧
    2017-09-09
  • Spring Data JPA中的Specification動態(tài)查詢詳解

    Spring Data JPA中的Specification動態(tài)查詢詳解

    Specification是一個設計模式,用于企業(yè)級應用開發(fā)中,其主要目的是將業(yè)務規(guī)則從業(yè)務邏輯中分離出來,在數據查詢方面,Specification可以定義復雜的查詢,使其更易于重用和測試,這篇文章主要介紹了Spring Data JPA中的Specification動態(tài)查詢詳解,需要的朋友可以參考下
    2023-07-07
  • 在maven中引入本地jar包的步驟

    在maven中引入本地jar包的步驟

    這篇文章主要介紹了在maven中引入本地jar包的步驟,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下
    2021-04-04
  • 為什么ConcurrentHashMap的key value不能為null,map可以?

    為什么ConcurrentHashMap的key value不能為null,map可以?

    這篇文章主要介紹了為什么ConcurrentHashMap的key value不能為null,map可以呢?具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • Java編程實現(xiàn)鄰接矩陣表示稠密圖代碼示例

    Java編程實現(xiàn)鄰接矩陣表示稠密圖代碼示例

    這篇文章主要介紹了Java編程實現(xiàn)鄰接矩陣表示稠密圖代碼示例,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • SpringBoot?整合Redis?數據庫的方法

    SpringBoot?整合Redis?數據庫的方法

    Redis是一個基于內存的日志型可持久化的緩存數據庫,保存形式為key-value格式,Redis完全免費開源,它使用ANSI?C語言編寫。這篇文章主要介紹了SpringBoot?整合Redis?數據庫的方法,需要的朋友可以參考下
    2018-03-03

最新評論