国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

AsyncContext優(yōu)雅實現(xiàn)HTTP長輪詢接口

這篇具有很好參考價值的文章主要介紹了AsyncContext優(yōu)雅實現(xiàn)HTTP長輪詢接口。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、背景

接到一個需求,實現(xiàn)方案時需要提供一個HTTP接口,接口需要hold住5-8秒,輪詢查詢數(shù)據(jù)庫,一旦數(shù)據(jù)庫中值有變化,取出變化的值進行處理,處理完成后返回響應(yīng)。這不就是長輪詢嗎,如何優(yōu)雅的實現(xiàn)呢?

在這之前先簡單介紹下長連接和短連接

HTTP長鏈接(Keep-Alive)
  • 概念: HTTP長鏈接是指客戶端與服務(wù)器在一次TCP連接上可以傳輸多個HTTP請求和響應(yīng)。在請求完成后,連接不會立即關(guān)閉,而是保持開放狀態(tài),等待可能的后續(xù)請求。

  • 優(yōu)勢:

    • 減少延遲: 長鏈接避免了每次請求都需要重新建立TCP連接的開銷,降低了通信延遲。
    • 減少資源占用: 不需要頻繁地打開和關(guān)閉連接,減少了服務(wù)器資源的占用。
  • 應(yīng)用場景:

    • 實時性要求高的應(yīng)用: 長鏈接適用于需要實時性響應(yīng)的應(yīng)用,例如即時通訊、實時更新等。
    • 資源加載優(yōu)化: 在Web開發(fā)中,適用于多個資源(如圖片、樣式表、腳本)的同時加載。
HTTP短連接
  • 概念: HTTP短連接是指每個HTTP請求都需要建立一個新的TCP連接,請求完成后立即關(guān)閉連接。

  • 優(yōu)勢:

    • 簡單: 短連接模式相對簡單,易于理解和實現(xiàn)。
    • 更好的控制: 對于某些資源密集型的應(yīng)用,短連接可以更好地控制資源的釋放。
  • 應(yīng)用場景:

    • 低并發(fā)場景: 當(dāng)并發(fā)請求數(shù)較低時,短連接可能更適用,因為它避免了長鏈接的開銷。
    • 資源密集型應(yīng)用: 對于服務(wù)器資源消耗較大的應(yīng)用,短連接可能更容易控制資源的釋放。
何為輪詢

所謂輪詢,即是在一個循環(huán)周期內(nèi)不斷發(fā)起請求來得到數(shù)據(jù)的機制。只要有請求的的地方,都可以實現(xiàn)輪詢,譬如各種事件驅(qū)動模型。它的長短是在于某次請求的返回周期。

1. 短輪詢

短輪詢指的是在循環(huán)周期內(nèi),不斷發(fā)起請求,每一次請求都立即返回結(jié)果,根據(jù)新1日數(shù)據(jù)對比決定是否使用這個結(jié)果。

2. 長輪詢

而長輪詢及是在請求的過程中,若是服務(wù)器端數(shù)據(jù)并沒有更新,那么則將這個連接掛起,直到服務(wù)器推送新的數(shù)據(jù),再返回,然后再進入循環(huán)周期。

長短輪詢和長短連接的區(qū)別
1. 第一個區(qū)別是決定的方式,

一個TCP連接是否為長連接,是通過設(shè)置HTTP的Connection Header來決定的,而且是需要兩邊都設(shè)置才有效。而一種輪詢方式是否為長輪詢,是根據(jù)服務(wù)端的處理方式來決定的,與客戶端沒有關(guān)系。

2. 第二個區(qū)別就是實現(xiàn)的方式

連接的長短是通過協(xié)議來規(guī)定和實現(xiàn)的。而輪詢的長短,是服務(wù)器通過編程的方式手動掛起請求來實現(xiàn)的。

二、方案設(shè)計

在 Spring 中,AsyncContext 是用于支持異步處理的一個重要的特性。它允許我們在 servlet 請求處理過程中,將長時間運行的操作放在一個單獨的線程中執(zhí)行,而不會阻塞其他請求的處理。

AsyncContext 在以下兩種情況下特別有用:

  1. 長時間運行的操作:當(dāng)我們需要執(zhí)行一些耗時的操作,例如網(wǎng)絡(luò)請求、數(shù)據(jù)庫查詢或其他 I/O 操作時,通過將這些操作放在一個新的線程中,可以避免阻塞 servlet 容器中的線程,提高應(yīng)用的并發(fā)性能。

  2. 推送異步響應(yīng):有時候,我們可能需要推送異步產(chǎn)生的響應(yīng),而不是等到所有操作都完成后再下發(fā)響應(yīng)。通過 AsyncContext,我們可以在任何時間點上觸發(fā)異步響應(yīng),將結(jié)果返回給客戶端。

使用 AsyncContext 的步驟如下:

  1. 在 servlet 中啟用異步模式:在 servlet 中,通過調(diào)用?startAsync()?方法,可以獲取到當(dāng)前請求的 AsyncContext 對象,從而啟用異步處理模式。
HttpServletRequest request = ...;
AsyncContext asyncContext = request.startAsync();
  1. 指定異步任務(wù):通過調(diào)用 AsyncContext 對象的?start()?方法,在新的線程中執(zhí)行需要異步處理的任務(wù)。
asyncContext.start(() -> {
    // 異步任務(wù)邏輯
});
  1. 提交響應(yīng):在異步任務(wù)完成后,可以調(diào)用 AsyncContext 對象的?complete()?方法,以表示異步操作完成。
asyncContext.complete();

需要注意的是,我們在使用 AsyncContext 時需要特別注意線程安全。由于異步任務(wù)在單獨的線程中執(zhí)行,所以可能存在并發(fā)問題。因此,在編寫異步任務(wù)邏輯時,需要注意線程安全性,使用合適的同步措施。

另外,AsyncContext 也支持超時設(shè)置、錯誤處理、事件監(jiān)聽等功能,這些可以通過相應(yīng)的方法和回調(diào)進行配置??梢愿鶕?jù)具體的需求使用這些功能來優(yōu)化異步處理的邏輯。

總結(jié)來說,Spring 的 AsyncContext 提供了方便的異步處理機制,可以提高應(yīng)用的并發(fā)性能,并支持推送異步響應(yīng),使得應(yīng)用更具有響應(yīng)性和可伸縮性。文章來源地址http://www.zghlxwxcb.cn/news/detail-702762.html

三、方案1

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.*;

@RestController
@RequestMapping("/api/test")
@Slf4j
public class AsyncTestController {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    private final ExecutorService timeoutChecker = new ThreadPoolExecutor(1,1,1000,TimeUnit.SECONDS,new ArrayBlockingQueue<>(1000));
    private static final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("longPolling-timeout-checker-%d").build();


//    private static boolean result = false;

    @PostMapping("/async")
    public void async(HttpServletRequest request, HttpServletResponse response) {
        // 創(chuàng)建AsyncContext
        AsyncContext asyncContext = request.startAsync(request, response);
        // 設(shè)置處理超時時間8s
        asyncContext.setTimeout(8000L);
        // asyncContext監(jiān)聽
        AsyncTestListener asyncListener = new AsyncTestListener(redisTemplate,asyncContext);
        asyncContext.addListener(asyncListener);
        // 定時處理業(yè)務(wù),處理成功后asyncContext.complete();完成異步請求
        asyncContext.start(asyncListener);
    }

    // 模擬業(yè)務(wù)處理完成
    @PostMapping("/set")
    public ResultModel notify(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
        return ResultModel.success();
    }

    @PostMapping("/get")
    public ResultModel get(String key) {
        String s = redisTemplate.opsForValue().get(key);
        return ResultModel.success(s);
    }

    @PostMapping("/del")
    public ResultModel del(String key) {
        redisTemplate.delete(key);
        return ResultModel.success();
    }
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import java.io.IOException;


@Slf4j
public class AsyncTestListener implements AsyncListener,Runnable {
    boolean isComplete;

    private RedisTemplate<String, String> redisTemplate;
    private AsyncContext asyncContext;
    public JdAsyncTestListener(RedisTemplate<String, String> redisTemplate, AsyncContext asyncContext) {
        this.redisTemplate = redisTemplate;
        this.asyncContext = asyncContext;
    }

    @Override
    public void run() {
        try {
            while(true){
                if(isComplete){
                    log.info("已經(jīng)退出");
                    break;
                }
                boolean b = redisTemplate.opsForValue().get(1) != null;
                log.info("獲取標(biāo)志位:"+b);
                Thread.sleep(300);
                if (b) {
                    asyncContext.getResponse().getWriter().print(1);
                    asyncContext.complete();
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onComplete(AsyncEvent asyncEvent) throws IOException {
        log.info("結(jié)束了");
        isComplete = true;

    }

    @Override
    public void onTimeout(AsyncEvent asyncEvent) throws IOException {
        log.info("超時了");
        isComplete = true;
    }

    @Override
    public void onError(AsyncEvent asyncEvent) throws IOException {

    }

    @Override
    public void onStartAsync(AsyncEvent asyncEvent) throws IOException {

    }
}

四、方案2

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

@Validated
@RestController
@RequestMapping("/api/test")
@Slf4j
public class TestController {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    private final ScheduledExecutorService timeoutChecker = new ScheduledThreadPoolExecutor(10, threadFactory);
    private static final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("longPolling-timeout-checker-%d").build();

    private static boolean result = false;

    private final boolean isTimeout = false;


    /**
     * 消息
     *
     * @return
     */
    @PostMapping("/test")
    public void callback(@RequestBody TestLongPollRequest testLongPollRequest, HttpServletRequest request, HttpServletResponse response) {
        // 創(chuàng)建AsyncContext
        AsyncContext asyncContext = request.startAsync(request, response);
        String test = LongPollRequest.getctomerId();
        // 設(shè)置處理超時時間8s
        asyncContext.setTimeout(8000L);
        // asyncContext監(jiān)聽
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent asyncEvent) throws IOException {
                log.info("onComplete={}", asyncEvent);
            }

            @Override
            public void onTimeout(AsyncEvent asyncEvent) throws IOException {
                log.info("onTimeout={}", asyncEvent);
                ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
                map.put("code", "500");                asyncContext.getResponse().getWriter().print(JSON.toJSONString(map));
                asyncContext.complete();
            }

            @Override
            public void onError(AsyncEvent asyncEvent) throws IOException {
                log.info("onError={}", asyncEvent);
            }

            @Override
            public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
                log.info("onStartAsync={}", asyncEvent);
            }
        });
        // 定時處理業(yè)務(wù),處理成功后asyncContext.complete();完成異步請求
        timeoutChecker.scheduleAtFixedRate(() -> {
            try {
                String redisKey = getRedisKey(customerId);
                String redisValue = redisTemplate.opsForValue().get(redisKey);
                result = StringUtils.isNotBlank(redisValue);
                if (result) {
                    //todo 長輪詢查詢數(shù)據(jù)庫。通過customerId查詢
                    send(test, redisValue);
                    ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
                    map.put("code", "200");
                    map.put("msg", redisValue);
                    asyncContext.getResponse().getWriter().print(JSON.toJSONString(map));
                    asyncContext.complete();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, 0, 100L, TimeUnit.MILLISECONDS);
    }

    /**
     * 發(fā)送消息
     */
    private void send(String test, String content) {
        
    }
  
}

到了這里,關(guān)于AsyncContext優(yōu)雅實現(xiàn)HTTP長輪詢接口的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 前端(二十三)——輪詢和長輪詢

    前端(二十三)——輪詢和長輪詢

    ??博主:小貓娃來啦 ??文章核心:實現(xiàn)客戶端與服務(wù)器實時通信的技術(shù)手段 現(xiàn)代Web應(yīng)用程序?qū)崟r通信的需求越來越高,為了滿足這種需求,輪詢和長輪詢成為了常用的技術(shù)手段。本文將深入探討輪詢和長輪詢的實現(xiàn)原理、優(yōu)缺點以及使用場景,并提供代碼示例,以幫助讀

    2024年02月03日
    瀏覽(16)
  • QNetworkAccessManager實現(xiàn)可手動中斷和超時機制的異步Http網(wǎng)絡(luò)接口

    Qt中的網(wǎng)絡(luò)訪問 API 是圍繞 QNetworkAccessManager 對象構(gòu)建的,該對象保存它發(fā)送的請求的通用配置和設(shè)置。因此實現(xiàn)Http請求必然需要使用QNetworkAccessManager 來開發(fā)。 需要注意的是:QNetworkAccessManager 是基于 QObject 的,所以只能在它所屬的線程中使用。 1.超時機制:利用QTimer定時,在

    2024年03月19日
    瀏覽(18)
  • 輪詢和長輪詢的講解和實戰(zhàn)

    輪詢和長輪詢的講解和實戰(zhàn)

    前言 當(dāng)今web應(yīng)用程序?qū)崟r通信的需求越來越高,為了滿足客戶需求,輪詢和長輪詢成為常用的技術(shù)手段。本文將深入講解一下輪詢實現(xiàn)原理、優(yōu)缺點和使用場景。 一、輪詢概念 輪詢是一種客戶端與服務(wù)器之間實時通信的技術(shù)手段。 基本原理: 客戶端定期發(fā)送請求來查詢

    2024年01月19日
    瀏覽(19)
  • 即時通訊:短輪詢、長輪詢、SSE 和 WebSocket 間的區(qū)別

    在現(xiàn)代 Web 開發(fā)中,即時通訊已經(jīng)成為許多應(yīng)用程序的重要組成部分。為了實現(xiàn)即時通訊,開發(fā)人員通常使用不同的技術(shù)和協(xié)議。本文將介紹四種常見的即時通訊實現(xiàn)方法:短輪詢、長輪詢、SSE(服務(wù)器發(fā)送事件)和 WebSocket,并探討它們之間的區(qū)別。 短輪詢是最簡單的即時通

    2024年02月12日
    瀏覽(27)
  • IM通信技術(shù)快速入門:短輪詢、長輪詢、SSE、WebSocket

    IM通信技術(shù)快速入門:短輪詢、長輪詢、SSE、WebSocket

    ??IM通信技術(shù)快速入門:短輪詢、長輪詢、SSE、WebSocket ☆* o(≧▽≦)o *☆嗨~我是IT·陳寒?? ?博客主頁:IT·陳寒的博客 ??該系列文章專欄:Java面試技巧 ??其他專欄:Java學(xué)習(xí)路線 Java面試技巧 Java實戰(zhàn)項目 AIGC人工智能 數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí) ??文章作者技術(shù)和水平有限,如果文中

    2024年02月05日
    瀏覽(23)
  • Tomcat長輪詢原理與源碼解析

    Tomcat長輪詢原理與源碼解析

    系列文章目錄和關(guān)于我 最近在看工作使用到的配置中心原理,發(fā)現(xiàn)大多數(shù)配置中心在推和拉模型上做的選擇出奇的一致選擇了 基于長輪詢的拉模型 基于拉模型的客戶端輪詢的方案 客戶端通過輪詢方式發(fā)現(xiàn)服務(wù)端的配置變更事件。輪詢的頻率決定了動態(tài)配置獲取的實時性。

    2023年04月16日
    瀏覽(21)
  • 優(yōu)雅終止 | 高雅模版 | 基于 go 的 http 庫實現(xiàn)

    優(yōu)雅終止 | 高雅模版 | 基于 go 的 http 庫實現(xiàn)

    博客原文 源碼地址 應(yīng)用開始關(guān)閉時, 對于服務(wù)器的連接 對已有連接: 等待其處理 拒絕新請求 是否需要將 cache 中數(shù)據(jù)保存到 db 釋放服務(wù)器資源 應(yīng)用啟動: 優(yōu)雅終止: 需監(jiān)聽的信號量 windows linux Server 一個 server 對應(yīng)一個 service 定義 其中使用 http.ServeMux 是為確保一個 server, 只能

    2024年02月21日
    瀏覽(23)
  • 互聯(lián)網(wǎng)大廠技術(shù)-HTTP請求-Springboot整合Feign更優(yōu)雅地實現(xiàn)Http服務(wù)調(diào)用

    互聯(lián)網(wǎng)大廠技術(shù)-HTTP請求-Springboot整合Feign更優(yōu)雅地實現(xiàn)Http服務(wù)調(diào)用

    目錄 一、SpringBoot快速整合Feign 1.添加Pom依賴 2.啟動類添加注解 3.引用Feign服務(wù) 二、為請求添加Header的3種方式 1.添加固定header 2.通過接口簽名添加header 3.動態(tài)添加header 三、為請求添加超時配置 1.默認(rèn)超時時間 3.超時異常 4.全局超時配置 5.為單個服務(wù)設(shè)置超時配置 四、為請求配

    2024年02月04日
    瀏覽(21)
  • golang http服務(wù)實現(xiàn)多ip監(jiān)聽,及優(yōu)雅重啟

    在工作中,有時需要對http服務(wù)實現(xiàn)多監(jiān)聽,http服務(wù)重啟等需求。大多數(shù)web框架只實現(xiàn)的是單ip監(jiān)聽,要實現(xiàn)多ip監(jiān)聽就需要循環(huán)監(jiān)聽ip; 而重啟http服務(wù),首先想到的是用endless來優(yōu)雅的實現(xiàn)服務(wù)的重啟,但是當(dāng)多ip監(jiān)聽時,一個項目不能用一個endLess,多了會報錯,且windows環(huán)境也

    2023年04月12日
    瀏覽(21)
  • 互聯(lián)網(wǎng)大廠技術(shù)-HTTP請求-Springboot整合Feign更優(yōu)雅地實現(xiàn)Http服務(wù)調(diào)用
no suitable HttpMessageConverter found for response type

    互聯(lián)網(wǎng)大廠技術(shù)-HTTP請求-Springboot整合Feign更優(yōu)雅地實現(xiàn)Http服務(wù)調(diào)用 no suitable HttpMessageConverter found for response type

    目錄 一、SpringBoot快速整合Feign 1.添加Pom依賴 2.啟動類添加注解 3.引用Feign服務(wù) 二、為請求添加Header的3種方式 1.添加固定header 2.通過接口簽名添加header 3.動態(tài)添加header 三、為請求添加超時配置 1.默認(rèn)超時時間 3.超時異常 4.全局超時配置 5.為單個服務(wù)設(shè)置超時配置 四、為請求配

    2024年02月11日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包