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

SpringBoot中使用異步線程導(dǎo)致Request請(qǐng)求頭丟失問(wèn)題的解決方法

 更新時(shí)間:2025年07月23日 10:22:41   作者:就胡編亂碼  
異步線程請(qǐng)求頭丟失的問(wèn)題通常發(fā)生在多線程環(huán)境中,特別是在使用 CompletableFuture 或其他異步編程模型時(shí),本文給大家詳細(xì)介紹了SpringBoot中使用異步線程導(dǎo)致Request請(qǐng)求頭丟失問(wèn)題的原因和解決方法,需要的朋友可以參考下

背景

異步線程請(qǐng)求頭丟失的問(wèn)題通常發(fā)生在多線程環(huán)境中,特別是在使用 CompletableFuture 或其他異步編程模型時(shí)。具體原因如下:

異步線程請(qǐng)求頭丟失的原因

當(dāng)主線程將任務(wù)提交到異步線程池執(zhí)行時(shí),當(dāng)前線程中的 RequestAttributes(包括請(qǐng)求頭等上下文信息)不會(huì)自動(dòng)傳遞到異步線程中。這是因?yàn)?RequestAttributes 是基于當(dāng)前線程的本地存儲(chǔ)(ThreadLocal)實(shí)現(xiàn)的,而異步線程是在不同的線程中執(zhí)行任務(wù),因此無(wú)法訪問(wèn)到主線程中的 RequestAttributes。這種情況下,異步線程執(zhí)行任務(wù)時(shí)會(huì)丟失請(qǐng)求頭等上下文信息。
為了確保異步線程能夠正確獲取請(qǐng)求上下文信息,需要在任務(wù)執(zhí)行前后顯式地設(shè)置和重置 RequestAttributes。

一、問(wèn)題描述

筆者在開(kāi)發(fā)中使用CompletableFuture去異步調(diào)用openFegin服務(wù),但是在傳遞過(guò)程中發(fā)現(xiàn)了問(wèn)題,原來(lái)存儲(chǔ)在header中的信息,在進(jìn)入其他服務(wù)后header中存儲(chǔ)的user信息都丟失了

CompletableFuture<R<Boolean>> orderCheckFuture = CompletableFuture.supplyAsync(() -> remoteBusinessService.checkUnfinishedOrder(SecurityConstants.INNER, userId));
CompletableFuture<R<Boolean>> taskCheckFuture = CompletableFuture.supplyAsync(() -> remoteInspectionService.checkUnfinishedTask(SecurityConstants.INNER, userId));
CompletableFuture.allOf(orderCheckFuture, taskCheckFuture).join();
R<Boolean> orderCheck = orderCheckFuture.join();
R<Boolean> taskCheck = taskCheckFuture.join();

這種寫(xiě)法就導(dǎo)致了請(qǐng)求頭信息丟失,服務(wù)調(diào)用的發(fā)起方在system服務(wù)模塊,header中的租戶id為12361

請(qǐng)求在到達(dá)business服務(wù)模塊或者inspection服務(wù)模塊時(shí),租戶id丟失,變成了默認(rèn)值9999

二、解決方案

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

CompletableFuture<R<Boolean>> orderCheckFuture = CompletableFuture.supplyAsync(() -> {
    RequestContextHolder.setRequestAttributes(requestAttributes);
    return remoteBusinessService.checkUnfinishedOrder(SecurityConstants.INNER, userId);
});

CompletableFuture<R<Boolean>> taskCheckFuture = CompletableFuture.supplyAsync(() -> {
    RequestContextHolder.setRequestAttributes(requestAttributes);
    return remoteInspectionService.checkUnfinishedTask(SecurityConstants.INNER, userId);
});

CompletableFuture.allOf(orderCheckFuture, taskCheckFuture).join();

R<Boolean> orderCheck = orderCheckFuture.join();
R<Boolean> taskCheck = taskCheckFuture.join();

先通過(guò)如下代碼獲取請(qǐng)求頭屬性

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

接著在異步線程中重新設(shè)置下異步線程所攜帶請(qǐng)求頭的信息,這樣就保證了請(qǐng)求頭的連續(xù)傳遞性

三、拓展

不想每次都在CompletableFuture中都寫(xiě)如下設(shè)置請(qǐng)求頭信息的代碼怎么辦?

RequestContextHolder.setRequestAttributes(requestAttributes);

筆者這里給出一個(gè)自認(rèn)為相對(duì)能減少點(diǎn)代碼量的解決方法(具體有無(wú)必要完全看個(gè)人)

自定義一個(gè)繼承CompletableFuture的類 CustomCompletableFuture

package com.zlbc.common.core.async;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.RequestAttributes;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Supplier;

/**
 * @author hulei
 * 異步線程傳遞請(qǐng)求頭,跨服務(wù)調(diào)用時(shí)需要傳遞請(qǐng)求頭信息
 */
public class CustomCompletableFuture<T> extends CompletableFuture<T> {

    public static <T> CustomCompletableFuture<T> supplyAsync(Supplier<T> supplier, Executor executor, RequestAttributes requestAttributes) {
        CustomCompletableFuture<T> future = new CustomCompletableFuture<>();
        executor.execute(() -> {
            try {
                RequestContextHolder.setRequestAttributes(requestAttributes);
                T result = supplier.get();
                future.complete(result);
            } catch (Exception e) {
                future.completeExceptionally(e);
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        });
        return future;
    }

    public static CustomCompletableFuture<Void> runAsync(Runnable runnable, Executor executor, RequestAttributes requestAttributes) {
        CustomCompletableFuture<Void> future = new CustomCompletableFuture<>();
        executor.execute(() -> {
            try {
                RequestContextHolder.setRequestAttributes(requestAttributes);
                runnable.run();
                future.complete(null);
            } catch (Exception e) {
                future.completeExceptionally(e);
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        });
        return future;
    }
}


使用方法如下,筆者設(shè)置了一個(gè)可以傳遞線程池的參數(shù)

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        
ExecutorService customExecutor = Executors.newFixedThreadPool(5);
        
CustomCompletableFuture<R<Boolean>> orderCheckFuture = CustomCompletableFuture.supplyAsync(
                () -> remoteBusinessService.checkUnfinishedOrder(SecurityConstants.INNER, userId),
                customExecutor,
                requestAttributes
);

CustomCompletableFuture<R<Boolean>> taskCheckFuture = CustomCompletableFuture.supplyAsync(
                () -> remoteInspectionService.checkUnfinishedTask(SecurityConstants.INNER, userId),
                customExecutor,
                requestAttributes
);

CompletableFuture.allOf(orderCheckFuture, taskCheckFuture).join();

R<Boolean> orderCheck = orderCheckFuture.join();
R<Boolean> taskCheck = taskCheckFuture.join();

這種寫(xiě)法就是減少了設(shè)置的代碼,傳一個(gè)參數(shù)進(jìn)去即可

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

這個(gè)可以寫(xiě)在某些全局工具類如ServletUtils

使用時(shí)如下獲取即可

RequestAttributes requestAttributes = ServletUtils.getRequestAttributes();

四、總結(jié)

本篇文章主要描述了筆者實(shí)際開(kāi)發(fā)中遇到的采用異步線程導(dǎo)致請(qǐng)求頭丟失的問(wèn)題,本文詳細(xì)介紹了問(wèn)題發(fā)生的場(chǎng)景和解決方法。實(shí)際可以從以下幾個(gè)方面考慮

  1. 顯式傳遞 RequestAttributes:
  • 在異步任務(wù)執(zhí)行前,獲取當(dāng)前線程的 RequestAttributes。
  • 在異步任務(wù)執(zhí)行時(shí),顯式地設(shè)置 RequestAttributes。
  • 在異步任務(wù)執(zhí)行后,重置 RequestAttributes,以避免影響后續(xù)任務(wù)。
  1. 使用自定義 CompletableFuture 實(shí)現(xiàn):
  • 創(chuàng)建一個(gè)自定義的 CompletableFuture 實(shí)現(xiàn),在任務(wù)執(zhí)行前后自動(dòng)設(shè)置和重置 RequestAttributes。
  • 這樣可以確保每個(gè)異步任務(wù)都能訪問(wèn)到正確的請(qǐng)求上下文信息。
  1. 使用 ThreadLocal 傳遞上下文信息:
  • 利用 ThreadLocal 將請(qǐng)求上下文信息(如請(qǐng)求頭等)封裝在一個(gè)對(duì)象中。
  • 在異步任務(wù)執(zhí)行前后,顯式地傳遞并設(shè)置這個(gè)對(duì)象。
  1. 使用 AOP(面向切面編程):
  • 通過(guò) AOP 在方法調(diào)用前后自動(dòng)設(shè)置和重置 RequestAttributes。
  • 這樣可以減少手動(dòng)設(shè)置和重置 RequestAttributes 的代碼量。
  1. 使用 Spring 提供的工具類:
  • 利用 Spring 提供的工具類(如 RequestContextHolder 和 RequestAttributes)來(lái)管理請(qǐng)求上下文。
  • 在異步任務(wù)執(zhí)行前后,顯式地設(shè)置和重置這些工具類的狀態(tài)。

通過(guò)上述方法,可以確保異步線程在執(zhí)行任務(wù)時(shí)能夠正確訪問(wèn)到請(qǐng)求上下文信息,從而避免請(qǐng)求頭丟失的問(wèn)題。對(duì)您有幫助的話,請(qǐng)關(guān)注點(diǎn)贊支持一波哦!

以上就是SpringBoot中使用異步線程導(dǎo)致Request請(qǐng)求頭丟失問(wèn)題的解決方法的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Request請(qǐng)求頭丟失的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • kafka與storm集群環(huán)境的安裝步驟詳解

    kafka與storm集群環(huán)境的安裝步驟詳解

    這篇文章主要給大家介紹了關(guān)于kafka與storm集群環(huán)境安裝步驟的相關(guān)資料,兩者并不是一定聯(lián)系的,寫(xiě)在一起主要是因?yàn)閮蓚€(gè)都是有zookeeper管理的,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • Java Optional解決空指針異常總結(jié)(java 8 功能)

    Java Optional解決空指針異常總結(jié)(java 8 功能)

    這篇文章主要介紹了Java Optional解決空指針異??偨Y(jié)(java 8 功能),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • SpringBoot--- SpringSecurity進(jìn)行注銷權(quán)限控制的配置方法

    SpringBoot--- SpringSecurity進(jìn)行注銷權(quán)限控制的配置方法

    這篇文章主要介紹了SpringBoot--- SpringSecurity進(jìn)行注銷,權(quán)限控制,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java實(shí)例化的幾種方法總結(jié)

    Java實(shí)例化的幾種方法總結(jié)

    這篇文章主要介紹了Java實(shí)例化的幾種方法總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Java String源碼分析并介紹Sting 為什么不可變

    Java String源碼分析并介紹Sting 為什么不可變

    這篇文章主要介紹了Java String源碼分析并介紹Sting 為什么不可變的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • 詳談java命令的本質(zhì)邏輯揭秘

    詳談java命令的本質(zhì)邏輯揭秘

    一個(gè)簡(jiǎn)單的java命令背后究竟做了些什么事情,很多朋友提出幾個(gè)問(wèn)題,下面帶領(lǐng)大家一起學(xué)習(xí)Java命令的本質(zhì)邏輯問(wèn)題,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • Java如何遠(yuǎn)程調(diào)用對(duì)方接口

    Java如何遠(yuǎn)程調(diào)用對(duì)方接口

    這篇文章主要介紹了Java如何遠(yuǎn)程調(diào)用對(duì)方接口問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java使用BigDecimal精確運(yùn)算浮點(diǎn)數(shù)

    Java使用BigDecimal精確運(yùn)算浮點(diǎn)數(shù)

    這篇文章主要介紹了Java使用BigDecimal精確運(yùn)算浮點(diǎn)數(shù),幫助大家更好的處理浮點(diǎn)數(shù)數(shù)據(jù),感興趣的朋友可以了解下
    2020-10-10
  • Java 調(diào)用Restful API接口的幾種方式(HTTPS)

    Java 調(diào)用Restful API接口的幾種方式(HTTPS)

    這篇文章主要介紹了Java 調(diào)用Restful API接口的幾種方式(HTTPS),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • Spring 中的循環(huán)引用問(wèn)題解決方法

    Spring 中的循環(huán)引用問(wèn)題解決方法

    這篇文章主要介紹了Spring 中的循環(huán)引用問(wèn)題解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-04-04

最新評(píng)論

繁峙县| 增城市| 蓬莱市| 安仁县| 彝良县| 渝北区| 上蔡县| 舒城县| 峡江县| 虹口区| 故城县| 五峰| 南投市| 措勤县| 巴塘县| 射洪县| 洛宁县| 晋中市| 呼图壁县| 福贡县| 会东县| 克什克腾旗| 宿迁市| 吉木萨尔县| 嘉禾县| 鞍山市| 桃源县| 大兴区| 胶州市| 黔西| 汤阴县| 轮台县| 饶河县| 宁陕县| 通榆县| 田东县| 巩留县| 庆安县| 泰来县| 泗水县| 信阳市|