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

SpringBoot中使用異步線程導致Request請求頭丟失問題的解決方法

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

背景

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

異步線程請求頭丟失的原因

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

一、問題描述

筆者在開發(fā)中使用CompletableFuture去異步調(diào)用openFegin服務(wù),但是在傳遞過程中發(fā)現(xiàn)了問題,原來存儲在header中的信息,在進入其他服務(wù)后header中存儲的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();

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

請求在到達business服務(wù)模塊或者inspection服務(wù)模塊時,租戶id丟失,變成了默認值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();

先通過如下代碼獲取請求頭屬性

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

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

三、拓展

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

RequestContextHolder.setRequestAttributes(requestAttributes);

筆者這里給出一個自認為相對能減少點代碼量的解決方法(具體有無必要完全看個人)

自定義一個繼承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
 * 異步線程傳遞請求頭,跨服務(wù)調(diào)用時需要傳遞請求頭信息
 */
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è)置了一個可以傳遞線程池的參數(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();

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

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

這個可以寫在某些全局工具類如ServletUtils

使用時如下獲取即可

RequestAttributes requestAttributes = ServletUtils.getRequestAttributes();

四、總結(jié)

本篇文章主要描述了筆者實際開發(fā)中遇到的采用異步線程導致請求頭丟失的問題,本文詳細介紹了問題發(fā)生的場景和解決方法。實際可以從以下幾個方面考慮

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

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

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

相關(guān)文章

  • 詳解JAVA設(shè)計模式之模板模式

    詳解JAVA設(shè)計模式之模板模式

    這篇文章主要介紹了詳解JAVA設(shè)計模式之模板模式的的相關(guān)資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06
  • java必學必會之網(wǎng)絡(luò)編程

    java必學必會之網(wǎng)絡(luò)編程

    java必學必會之網(wǎng)絡(luò)編程,學習了解java網(wǎng)絡(luò)編程、網(wǎng)絡(luò)通信協(xié)議、TCP協(xié)議和UDP協(xié)議,對各個協(xié)議進行深入學習,做到必學必會
    2015-12-12
  • java 生成二維碼實例

    java 生成二維碼實例

    這篇文章主要介紹了java 生成二維碼的實例,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-07-07
  • 淺談springboot @Repository與@Mapper的區(qū)別

    淺談springboot @Repository與@Mapper的區(qū)別

    本文主要介紹了淺談springboot @Repository與@Mapper的區(qū)別,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • spring?retry方法調(diào)用失敗重試機制示例解析

    spring?retry方法調(diào)用失敗重試機制示例解析

    這篇文章主要為大家介紹了spring?retry方法調(diào)用失敗重試機制的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • Java中的內(nèi)存區(qū)域(堆、棧、方法區(qū)等)分別存儲什么詳解

    Java中的內(nèi)存區(qū)域(堆、棧、方法區(qū)等)分別存儲什么詳解

    Java把內(nèi)存分成兩種,一種叫做棧內(nèi)存,一種叫做堆內(nèi)存,下面這篇文章主要介紹了Java中的內(nèi)存區(qū)域(堆、棧、方法區(qū)等)分別存儲什么的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-07-07
  • Java游戲開發(fā)之俄羅斯方塊的實現(xiàn)

    Java游戲開發(fā)之俄羅斯方塊的實現(xiàn)

    俄羅斯方塊是一個最初由阿列克謝帕吉特諾夫在蘇聯(lián)設(shè)計和編程的益智類視頻游戲。本文和大家分享了利用Java語言實現(xiàn)這一經(jīng)典的小游戲的示例代碼,需要的可以參考一下
    2022-05-05
  • Junit springboot打印測試方法信息

    Junit springboot打印測試方法信息

    這篇文章主要介紹了Junit springboot打印測試方法信息,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • Java中基于Shiro,JWT實現(xiàn)微信小程序登錄完整例子及實現(xiàn)過程

    Java中基于Shiro,JWT實現(xiàn)微信小程序登錄完整例子及實現(xiàn)過程

    這篇文章主要介紹了Java中基于Shiro,JWT實現(xiàn)微信小程序登錄完整例子 ,實現(xiàn)了小程序的自定義登陸,將自定義登陸態(tài)token返回給小程序作為登陸憑證。需要的朋友可以參考下
    2018-11-11
  • 解決Maven項目報錯:failed?to?execute?goal?org.apache.maven.plugins:maven-compiler-plugin:3.13.0的問題

    解決Maven項目報錯:failed?to?execute?goal?org.apache.maven.plug

    這篇文章主要介紹了解決Maven項目報錯:failed?to?execute?goal?org.apache.maven.plugins:maven-compiler-plugin:3.13.0的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05

最新評論