最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java 利用DeferredResult實(shí)現(xiàn)http輪詢實(shí)時(shí)返回?cái)?shù)據(jù)接口

 更新時(shí)間:2021年03月31日 10:13:50   作者:bridgeli  
這篇文章主要介紹了Java 利用 DeferredResult 實(shí)現(xiàn) http 輪詢實(shí)時(shí)返回?cái)?shù)據(jù)接口,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下

今天這篇文章呢,不難,其實(shí)是解答我一直以來心里的一個(gè)疑問。是這樣的,之前看五八技術(shù)委員會(huì)主席沈劍老師的公眾號(hào)架構(gòu)師之路的一篇文章:http 如何像 tcp 一樣實(shí)時(shí)的收消息,里面其中的一個(gè)方案是用 http 短連接輪詢的方式實(shí)現(xiàn)“偽長連接”。但是對(duì)于輪詢,我們的第一反應(yīng)肯定是有延時(shí),但是標(biāo)題不是說的是實(shí)時(shí)嗎?當(dāng)然我們可以把輪詢的時(shí)長縮短一些,先不說這樣大部分時(shí)間的輪詢調(diào)用,可能都沒消息返回,造成服務(wù)器資源浪費(fèi),輪詢時(shí)間再短也是有延時(shí)啊,所以難道是偽實(shí)時(shí)?反正一般消息延時(shí)個(gè)三五秒,甚至十秒八秒一分鐘,大家也不會(huì)在意,只會(huì)認(rèn)為對(duì)方返回慢,對(duì)不起,這是我們程序員的鍋,但是 http 真的不能實(shí)現(xiàn)實(shí)時(shí)嗎?沈劍老師提出了一種方法:首選 webim 和 webserver 之間建立一條 http 連接,專門用作消息通道,這條連接叫 http 消息連接。然后會(huì)有如下處理:

1. 沒有消息到達(dá)的時(shí)候,這個(gè) http 消息連接將被夯住,不返回,由于 http 是短連接,這個(gè) http 消息連接最多被夯住 90 秒,就會(huì)被斷開(這是瀏覽器或者 webserver 的行為);

2. 在 1 的情況下,如果 http 消息連接被斷開,立馬再發(fā)起一個(gè) http 消息連接;

此時(shí)在在 1 和 2 的配合下,瀏覽器與 webserver 之間將永遠(yuǎn)有一條消息連接在,然后還有一種情況

3. 每次收到消息時(shí),這個(gè)消息連接就能及時(shí)將消息帶回瀏覽器頁面,并且在返回后,會(huì)立馬再發(fā)起一個(gè) http 消息連接

這樣就能做到使用 http 端連接輪詢的方式實(shí)現(xiàn)了實(shí)時(shí)收消息。不過需要說明的是,其實(shí)還有一種情況:消息到達(dá)時(shí),上一個(gè) http 消息連接正在返回,也就是第二種情況的時(shí)候突然來了一個(gè)消息,此時(shí)沒有 http 消息連接可用。雖然理論上 http 消息連接的返回是瞬時(shí)的,沒有消息連接可用出現(xiàn)的概率極小,但是根據(jù)墨菲定律我們知道,這種情況肯定會(huì)出現(xiàn),所以這種情況下我們可以將消息暫存入消息池中,下一個(gè)消息連接到達(dá)后,無需等待,直接去消息池中取消息,將將消息帶回,然后立刻返回生成新的消息連接即可。

不過以上都不是今天這篇文章的重點(diǎn),和今天這篇文章的標(biāo)題也沒有任何關(guān)系。重點(diǎn)是當(dāng)時(shí)看了沈劍老師的這篇文章后我一直有一個(gè)疑問:第一步的時(shí)候如何夯住?總不能 sleep 吧,這多不優(yōu)雅啊,由于一直以為沒有遇到過類似的需求,所以這么幾年來我也沒深究這個(gè)問題,但是心里確實(shí)一直記著,直到前一段時(shí)間,聽馬士兵教育的公開課,當(dāng)時(shí)再講類似的問題的時(shí)候提到了夯住 http 的連接(具體是哪個(gè)問題,還真不記得了),雖然當(dāng)時(shí)上課的老師沒提怎么實(shí)現(xiàn),但是評(píng)論區(qū)我問了一下,如何夯住不返回?然后有一個(gè)同學(xué)回復(fù)說,用 DeferredResult,然后下課后搜了一下資料,果然可以,如下是實(shí)現(xiàn)的筆記,所以這才是重點(diǎn),希望對(duì)有這個(gè)疑問的同學(xué)也有一點(diǎn)幫助。

1. 消息返回實(shí)體類,大家可以根據(jù)實(shí)際情況,自己定義即可:

package cn.bridgeli.deferredresulttest.entity;
 
import lombok.Data;
import lombok.Getter;
 
/**
 * @author bridgeli
 */
@Data
public class DeferredResultResponse {
    private Integer code;
    private String msg;
 
    public enum Msg {
        TIMEOUT("超時(shí)"),
        FAILED("失敗"),
        SUCCESS("成功");
 
        @Getter
        private String desc;
 
        Msg(String desc) {
            this.desc = desc;
        }
    }
}

2. controller 接口:

package cn.bridgeli.deferredresulttest.controller;
 
import cn.bridgeli.deferredresulttest.entity.DeferredResultResponse;
import cn.bridgeli.deferredresulttest.service.DeferredResultService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
 
import javax.annotation.Resource;
 
 
/**
 * @author bridgeli
 */
@RestController
@RequestMapping(value = "/deferred-result")
public class DeferredResultController {
 
    @Resource
    private DeferredResultService deferredResultService;
 
    /**
     * 為了方便測(cè)試,簡(jiǎn)單模擬一個(gè)
     * 多個(gè)請(qǐng)求用同一個(gè)requestId會(huì)出問題
     */
    private final String requestId = "test";
 
 
    @GetMapping(value = "/get")
    public DeferredResult<DeferredResultResponse> get(@RequestParam(value = "timeout", required = false, defaultValue = "10000") Long timeout) {
        DeferredResult<DeferredResultResponse> deferredResult = new DeferredResult<>(timeout);
 
        deferredResultService.process(requestId, deferredResult);
 
        return deferredResult;
    }
 
    /**
     * 設(shè)置DeferredResult對(duì)象的result屬性,模擬異步操作
     *
     * @param desired
     * @return
     */
    @GetMapping(value = "/result")
    public String settingResult(@RequestParam(value = "desired", required = false, defaultValue = "成功") String desired) {
        DeferredResultResponse deferredResultResponse = new DeferredResultResponse();
        if (DeferredResultResponse.Msg.SUCCESS.getDesc().equals(desired)) {
            deferredResultResponse.setCode(HttpStatus.OK.value());
            deferredResultResponse.setMsg(desired);
        } else {
            deferredResultResponse.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
            deferredResultResponse.setMsg(DeferredResultResponse.Msg.FAILED.getDesc());
        }
        deferredResultService.settingResult(requestId, deferredResultResponse);
 
        return "Done";
    }
}

其中:/get 接口模擬沈劍老師說的消息連接,/result 接口模擬有一條新消息來了,然后 /get 接口會(huì)立即返回。主要注意的是 requestId,在實(shí)際項(xiàng)目中不能使用同一個(gè),否則會(huì)出現(xiàn)問題,這個(gè)測(cè)一下就知道了,也很容易想到原因。

3. service 實(shí)現(xiàn):

package cn.bridgeli.deferredresulttest.service;
 
import cn.bridgeli.deferredresulttest.entity.DeferredResultResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;
 
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
 
/**
 * @author bridgeli
 */
@Service
public class DeferredResultService {
 
    private Map<String, Consumer<DeferredResultResponse>> taskMap;
 
    public DeferredResultService() {
        taskMap = new ConcurrentHashMap<>();
    }
 
    /**
     * 將請(qǐng)求id與setResult映射
     *
     * @param requestId
     * @param deferredResult
     */
    public void process(String requestId, DeferredResult<DeferredResultResponse> deferredResult) {
        // 請(qǐng)求超時(shí)的回調(diào)函數(shù)
        deferredResult.onTimeout(() -> {
            taskMap.remove(requestId);
            DeferredResultResponse deferredResultResponse = new DeferredResultResponse();
            deferredResultResponse.setCode(HttpStatus.REQUEST_TIMEOUT.value());
            deferredResultResponse.setMsg(DeferredResultResponse.Msg.TIMEOUT.getDesc());
            deferredResult.setResult(deferredResultResponse);
        });
 
        Optional.ofNullable(taskMap)
                .filter(t -> !t.containsKey(requestId))
                .orElseThrow(() -> new IllegalArgumentException(String.format("requestId=%s is existing", requestId)));
 
        taskMap.putIfAbsent(requestId, deferredResult::setResult);
    }
 
    /**
     * 這里相當(dāng)于異步的操作方法
     * 設(shè)置DeferredResult對(duì)象的setResult方法
     *
     * @param requestId
     * @param deferredResultResponse
     */
    public void settingResult(String requestId, DeferredResultResponse deferredResultResponse) {
        if (taskMap.containsKey(requestId)) {
            Consumer<DeferredResultResponse> deferredResultResponseConsumer = taskMap.get(requestId);
            // 這里相當(dāng)于DeferredResult對(duì)象的setResult方法
            deferredResultResponseConsumer.accept(deferredResultResponse);
            taskMap.remove(requestId);
        }
    }
 
}

文章最后,我想在說明另外一個(gè)問題,我們利用 DeferredResult 實(shí)現(xiàn)了 http 輪詢返回,其實(shí)換個(gè)思路想問題,我們是不是也實(shí)現(xiàn)了 http 接口延時(shí)返回?所以如果你有延時(shí)返回的需求,同樣可以借助 DeferredResult 實(shí)現(xiàn)。

以上就是Java 利用 DeferredResult 實(shí)現(xiàn) http 輪詢實(shí)時(shí)返回?cái)?shù)據(jù)接口的詳細(xì)內(nèi)容,更多關(guān)于Java 實(shí)現(xiàn) http 輪詢實(shí)時(shí)返回?cái)?shù)據(jù)接口的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring.Net IOC依賴注入原理流程解析

    Spring.Net IOC依賴注入原理流程解析

    這篇文章主要介紹了Spring.Net IOC依賴注入原理流程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Spring高階用法之自定義業(yè)務(wù)對(duì)象組件化

    Spring高階用法之自定義業(yè)務(wù)對(duì)象組件化

    這篇文章主要介紹了Spring高階用法之自定義業(yè)務(wù)對(duì)象組件化,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Java編程實(shí)現(xiàn)從給定范圍內(nèi)隨機(jī)N個(gè)不重復(fù)數(shù)生成隨機(jī)數(shù)的方法小結(jié)

    Java編程實(shí)現(xiàn)從給定范圍內(nèi)隨機(jī)N個(gè)不重復(fù)數(shù)生成隨機(jī)數(shù)的方法小結(jié)

    這篇文章主要介紹了Java編程實(shí)現(xiàn)從給定范圍內(nèi)隨機(jī)N個(gè)不重復(fù)數(shù)生成隨機(jī)數(shù)的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了java根據(jù)指定范圍生成不重復(fù)隨機(jī)數(shù)的相關(guān)操作技巧,需要的朋友可以參考下
    2017-04-04
  • 必須了解的高階JAVA枚舉特性!

    必須了解的高階JAVA枚舉特性!

    這篇文章主要介紹了必須了解的高階JAVA枚舉特性!幫助大家更好的理解和學(xué)習(xí)Java枚舉的相關(guān)知識(shí),感興趣的朋友可以了解下
    2021-01-01
  • MyBatisPlus 封裝分頁方法示例

    MyBatisPlus 封裝分頁方法示例

    本文主要介紹了基于MybatisPlus的分頁插件封裝,包括分頁結(jié)果對(duì)象、查詢對(duì)象的封裝,以及對(duì)象轉(zhuǎn)換處理,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-12-12
  • Java?List排序4種寫法整理

    Java?List排序4種寫法整理

    這篇文章主要給大家介紹了關(guān)于Java?List排序4種寫法整理的相關(guān)資料,在有的時(shí)候我們會(huì)需要對(duì)List進(jìn)行排序,在Java中如何實(shí)現(xiàn)呢,本文記錄一下Java中對(duì)List的幾種排序方式,需要的朋友可以參考下
    2023-08-08
  • java方法及this關(guān)鍵字原理分析詳解

    java方法及this關(guān)鍵字原理分析詳解

    本篇文章主要講解了對(duì)java方法和this關(guān)鍵字的用法及原理分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-10-10
  • 舉例解析Java的圖像緩沖技術(shù)的使用

    舉例解析Java的圖像緩沖技術(shù)的使用

    這篇文章主要介紹了Java的圖像緩沖技術(shù)的使用,使用到了Java的awt.image包,需要的朋友可以參考下
    2015-10-10
  • Java面向?qū)ο筮x擇題總結(jié)歸納

    Java面向?qū)ο筮x擇題總結(jié)歸納

    今天小編就為大家分享一篇關(guān)于Java面向?qū)ο筮x擇題總結(jié)歸納,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • spring整合JMS實(shí)現(xiàn)同步收發(fā)消息(基于ActiveMQ的實(shí)現(xiàn))

    spring整合JMS實(shí)現(xiàn)同步收發(fā)消息(基于ActiveMQ的實(shí)現(xiàn))

    本篇文章主要介紹了spring整合JMS實(shí)現(xiàn)同步收發(fā)消息(基于ActiveMQ的實(shí)現(xiàn)),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10

最新評(píng)論

柳林县| 邵阳市| 张家川| 来凤县| 瓦房店市| 乐亭县| 宣化县| 英德市| 濉溪县| 英超| 武隆县| 光泽县| 巫山县| 深州市| 临泽县| 沈丘县| 宣化县| 龙岩市| 常德市| 西充县| 棋牌| 得荣县| 中宁县| 德化县| 商城县| 钟山县| 阜平县| 阿尔山市| 奉新县| 寿光市| 吴堡县| 乌拉特中旗| 周宁县| 牡丹江市| 临沭县| 连州市| 濮阳市| 新野县| 乐平市| 苏尼特右旗| 文水县|