日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

SpringCloud微服務中Feign如何傳遞用戶Token,并保證多線程環境也可適用?

來源: 責編: 時間:2024-03-27 09:23:21 249觀看
導讀大家好,我是飄渺。在上一篇文章中,我們解決了網關層認證后向后端服務傳遞用戶信息的問題。今天我們來解決另外一個問題:如何在 OpenFeign 中傳遞 Token,并且保證多線程情況下也能適用。這是DDD&微服務系列文章的第34篇,歡

大家好,我是飄渺。0f428資訊網——每日最新資訊28at.com

在上一篇文章中,我們解決了網關層認證后向后端服務傳遞用戶信息的問題。今天我們來解決另外一個問題:如何在 OpenFeign 中傳遞 Token,并且保證多線程情況下也能適用。0f428資訊網——每日最新資訊28at.com

這是DDD&微服務系列文章的第34篇,歡迎持續關注!0f428資訊網——每日最新資訊28at.com

為了方便演示,首先定義一個接口,在接口中通過 Feign 調用其他服務:0f428資訊網——每日最新資訊28at.com

@Operation(summary = "用戶測試接口")  @GetMapping("/api/pd/customer/info")  public String info() {            String currentUser = UserContextHolder.getInstance().getCurrentUser();            log.info("feign調用方獲取當前登錄用戶:" + currentUser);       //通過feign調用遠程服務    String info = experimentClient.info();        log.info("遠程獲取用戶:" + info);    return currentUser;  }

然后在遠程接口中通過上文定義的UserContextHolder對象獲取用戶信息:0f428資訊網——每日最新資訊28at.com

@GetMapping("/api/pd/experiment/info")  public String userInfo() {        String currentUser = UserContextHolder.getInstance().getCurrentUser();        log.info("feign被調用方獲取userToken : {} ",currentUser);        return currentUser == null ? "" : currentUser;  }

0f428資訊網——每日最新資訊28at.com

圖片圖片0f428資訊網——每日最新資訊28at.com

通過調用結果可知,當使用OpenFeign調用遠程服務時,接口是無法獲取到用戶 ID 的。0f428資訊網——每日最新資訊28at.com

常規解決辦法

在使用OpenFeign請求其他服務接口時,默認不攜帶header信息,這樣就導致無法攜帶登錄用戶信息。常規情況下,我們只需要在使用 OpenFeign 調用時先從 Header 獲取 Token 信息,放入新請求即可,在項目中可以定義一個OpenFeign的攔截器來實現此功能,代碼如下所示:0f428資訊網——每日最新資訊28at.com

public class FeignRequestConfiguration {        @Bean      public RequestInterceptor requestInterceptor(){          return new RequestInterceptor() {              @Override              public void apply(RequestTemplate template) {                  RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();                  ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;                    // 當主線程的請求執行完畢后,Servlet容器會被銷毀當前的Servlet,因此在這里需要做判空                  if (attributes != null) {                      HttpServletRequest request = attributes.getRequest();                        // 獲取userId 并傳遞 userId                                        String userId = request.getHeader(CommonConstant.X_CLIENT_TOKEN);                      if (StringUtils.hasText(userId)) {                          template.header(CommonConstant.X_CLIENT_TOKEN, userId);                      }                  }              }          };      }  }

經過上述配置以后再次調用即可在 Feign 接口中也獲取到用戶ID,如下圖所示:0f428資訊網——每日最新資訊28at.com

圖片圖片0f428資訊網——每日最新資訊28at.com

異步調用

上面是單線程的情況,假如我們在當前線程中又開啟了子線程去進行 Feign 調用,那么是無法從 RequestContextHolder 獲取到 Header 的。測試代碼如下:0f428資訊網——每日最新資訊28at.com

public String info() {            String currentUser = UserContextHolder.getInstance().getCurrentUser();            log.info("feign調用方獲取當前登錄用戶:" + currentUser);        CompletableFuture<String> infoFuture = CompletableFuture.supplyAsync(experimentClient::info,executor);    String info = "";      try{          info = infoFuture.get();      } catch (Exception e) {          e.printStackTrace();          throw new RuntimeException(e);      }        log.info("遠程獲取用戶:" + info);        return currentUser;  }

在上述代碼中,通過 CompletableFuture 開啟異步線程去調用 experimentClient ,可以發現此時無法獲取到用戶信息,效果如下所示:0f428資訊網——每日最新資訊28at.com

圖片圖片0f428資訊網——每日最新資訊28at.com

0f428資訊網——每日最新資訊28at.com

出現上述問題的原因是,RequestContextHolder.getRequestAttributes() 方法里面使用的一個 ThreadLocal,默認不是線程共享的,源碼如下:0f428資訊網——每日最新資訊28at.com

public static RequestAttributes getRequestAttributes() {      RequestAttributes attributes = requestAttributesHolder.get();      if (attributes == null) {         attributes = inheritableRequestAttributesHolder.get();      }      return attributes;  }

所以主線程調用子線程時,無法獲取到主線程請求里面的 RequestAttributes。0f428資訊網——每日最新資訊28at.com

解決辦法

原因已經清楚了,繼續觀察 RequestContextHolder.getRequestAttributes() 方法源碼,注意到如果當前線程拿不到 RequestAttributes ,它會從 inheritableRequestAttributesHolder 里面拿,再仔細觀察發現源碼設置 RequestAttributes 到 ThreadLocal 的時候有這樣一個重載方法。0f428資訊網——每日最新資訊28at.com

/** * 給當前線程綁定屬性 * @param inheritable 是否要將屬性暴露給子線程 */public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {      ......}

這看起來符合我們的要求,只需要在主線程調用其他線程前將 RequestAttributes 對象設置為子線程共享,就能把 Header 等信息傳遞下去。0f428資訊網——每日最新資訊28at.com

所以,在異步調用 Feign 接口時添加如下代碼即可:0f428資訊網——每日最新資訊28at.com

RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(),true);CompletableFuture<String> infoFuture = CompletableFuture.supplyAsync(experimentClient::info,executor);......

再次執行發現,是可以獲取到 userId 的。0f428資訊網——每日最新資訊28at.com

這里使用CompletableFuture異步調用時需要使用自定義線程池,而不能使用默認線程池ForkJoinPool,這是為什么呢?0f428資訊網——每日最新資訊28at.com

最佳解決方案

雖然可以在異步調用時設置 RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true); 可以實現請求頭透傳,但是每次調用都需要加上這一句,實現上還略顯麻煩。0f428資訊網——每日最新資訊28at.com

并且我們知道了獲取不到請求頭的原因是子線程無法獲取主線程的 header 屬性,那么我們只需要定義一個數據結構,使用 InheritableThreadLocal 在內存中保存一份 header 屬性即可。在上篇文章中通過網關進行 UserID 透傳時我們是使用 ThreadLocal 保存數據,現在只需要將其換成 InheritableThreadLocal,同時在 RequestInterceptor#apply() 方法中不再通過請求頭獲取而是直接從 InheritableThreadLocal 中獲取數據。0f428資訊網——每日最新資訊28at.com

實現過程如下:0f428資訊網——每日最新資訊28at.com

1、重命名并修改數據結構:0f428資訊網——每日最新資訊28at.com

首先,將 UserContextHolder 重命名為 RequestHeaderHolder,同時使用 InheritableThreadLocal 替換 ThreadLocal,以便子線程也能獲取數據。0f428資訊網——每日最新資訊28at.com

public class RequestHeaderHolder {    private final ThreadLocal<Map<String,String>> REQUEST_HEADER_HOLDER;    //使用InheritableThreadLocal,使得共享變量可被子線程繼承    private RequestHeaderHolder() {        this.REQUEST_HEADER_HOLDER = new InheritableThreadLocal<>() {            @Override            protected Map<String, String> initialValue() {                return new HashMap<>();            }        };    }     public String getCurrentUser(){        return this.REQUEST_HEADER_HOLDER.get().get(CommonConstant.X_CLIENT_TOKEN);   }  ......}

2、修改請求攔截器:0f428資訊網——每日最新資訊28at.com

將請求攔截器 UserTokenInterceptor 重命名為 RequestHeaderInterceptor,并將請求頭放入 RequestHeaderHolder 中。0f428資訊網——每日最新資訊28at.com

@Slf4jpublic class RequestHeaderInterceptor implements HandlerInterceptor {        @Override    public boolean preHandle(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) throws Exception {        Enumeration<String> headerNames = request.getHeaderNames();        RequestHeaderHolder requestHeaderHolder = RequestHeaderHolder.getInstance();        //重新設置請求頭        while (headerNames.hasMoreElements()){            String key = headerNames.nextElement();            requestHeaderHolder.set(key,request.getHeader(key));        }        return true;    }       ......}

3、修改 Feign 配置類:在 FeignRequestConfiguration 中不再從 RequestContextHolder 獲取數據,而是從 RequestHeaderHolder 獲取數據。0f428資訊網——每日最新資訊28at.com

@Slf4jpublic class FeignRequestConfiguration {    @Bean    public RequestInterceptor requestInterceptor(){        return template -> {            Map<String, String> headerMap = RequestHeaderHolder.getInstance().get();            if(headerMap != null){                headerMap.forEach((key, value) -> {                                       template.header(key, value);                });            }        };    }}

通過上面的改造,不管是同步調用還是子線程異步調用都可以直接通過RequestHeaderHolder.getInstance().getCurrentUser();獲取用戶信息,并且調用方無須做任何改動。0f428資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-79599-0.htmlSpringCloud微服務中Feign如何傳遞用戶Token,并保證多線程環境也可適用?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 你的Css選擇器可視化備忘錄

下一篇: 面試官:只知道v-model是modelValue語法糖,那你可以走了

標簽:
  • 熱門焦點
  • 直屏旗艦來了 iQOO 12和K70 Pro同臺競技

    旗艦機基本上使用的都是雙曲面屏幕,這就讓很多喜歡直屏的愛好者在苦等一款直屏旗艦,這次,你們等到了。據博主數碼閑聊站帶來的最新爆料稱,Redmi下代旗艦K70 Pro和iQOO 12兩款手
  • 得物效率前端微應用推進過程與思考

    一、背景效率工程隨著業務的發展,組織規模的擴大,越來越多的企業開始意識到協作效率對于企業團隊的重要性,甚至是決定其在某個行業競爭中突圍的關鍵,是企業長久生存的根本。得物
  • 十個簡單但很有用的Python裝飾器

    裝飾器(Decorators)是Python中一種強大而靈活的功能,用于修改或增強函數或類的行為。裝飾器本質上是一個函數,它接受另一個函數或類作為參數,并返回一個新的函數或類。它們通常用
  • 虛擬鍵盤 API 的妙用

    你是否在遇到過這樣的問題:移動設備上有一個固定元素,當激活虛擬鍵盤時,該元素被隱藏在了鍵盤下方?多年來,這一直是 Web 上的默認行為,在本文中,我們將探討這個問題、為什么會發生
  • 三分鐘白話RocketMQ系列—— 如何發送消息

    我們知道RocketMQ主要分為消息 生產、存儲(消息堆積)、消費 三大塊領域。那接下來,我們白話一下,RocketMQ是如何發送消息的,揭秘消息生產全過程。注意,如果白話中不小心提到相關代
  • 10天營收超1億美元,《星鐵》比《原神》差在哪?

    來源:伯虎財經作者:陳平安即便你沒玩過《原神》,你一定聽說過的它的大名。恨它的人把《原神》開服那天稱作是中國游戲史上最黑暗的一天,有粉絲因為索尼在PS平臺上線《原神》,怒而
  • 品牌洞察丨服務本地,美團直播成效幾何?

    來源:17PR7月11日,美團App首頁推薦位出現&ldquo;美團直播&rdquo;的固定入口。在直播聚合頁面,外賣&ldquo;神槍手&rdquo;直播間、美團旅行直播間、美團買菜直播間等均已上線,同時
  • 小米MIX Fold 3下月亮相:今年唯一無短板的全能折疊屏

    這段時間以來,包括三星、一加、榮耀等等有不少品牌旗下的最新折疊屏旗艦都有新的進展,其中榮耀、三星都已陸續發布了最新的折疊屏旗艦,尤其號榮耀Magi
  • 回歸OPPO兩年,一加贏了銷量,輸了品牌

    成為OPPO旗下主打性能的先鋒品牌后,一加屢創佳績。今年618期間,一加手機全渠道銷量同比增長362%,憑借一加 11、一加 Ace 2、一加 Ace 2V三款爆品,一加
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
国产一区欧美| 欧美另类99xxxxx| 午夜精品一区二区三区四区| 欧美一区二区三区另类| 久久久久久电影| 欧美高清在线一区二区| 欧美日韩国产专区| 国产精品系列在线| 亚洲国产精品高清久久久| 日韩视频永久免费| 欧美一二区视频| 欧美国产1区2区| 国产精品日韩二区| 激情五月婷婷综合| aaa亚洲精品一二三区| 欧美中文字幕在线观看| 欧美激情欧美激情在线五月| 国产精品天美传媒入口| 亚洲国产日韩欧美在线图片| 亚洲免费影视第一页| 久久综合给合久久狠狠色 | 久久精品一本| 欧美日韩国产a| 国产综合18久久久久久| 一区二区欧美在线| 久色成人在线| 国产精品丝袜白浆摸在线| 亚洲精华国产欧美| 欧美在线1区| 欧美日韩亚洲一区三区| 伊人成人网在线看| 亚洲欧美高清| 欧美另类人妖| 精品盗摄一区二区三区| 亚洲综合日韩在线| 欧美成人亚洲| 国产一区深夜福利| 亚洲一二三区精品| 欧美激情欧美激情在线五月| 国产在线视频欧美一区二区三区| 一本到12不卡视频在线dvd| 久久亚洲私人国产精品va| 国产精品一区久久| 一本色道久久综合亚洲精品婷婷 | 欧美日韩国产页| 在线观看日韩国产| 欧美一区二区三区四区在线 | 午夜精品久久久久久久99黑人| 欧美高清在线精品一区| 国产一在线精品一区在线观看| 亚洲视频精选| 欧美日韩成人一区| 亚洲国产专区校园欧美| 久久久久九九九| 国产模特精品视频久久久久| 亚洲午夜免费视频| 欧美日韩成人综合天天影院| 亚洲国产精品一区制服丝袜| 久久久99爱| 国模吧视频一区| 午夜精品区一区二区三| 国产精品扒开腿做爽爽爽软件 | 在线高清一区| 久久久噜噜噜久久中文字幕色伊伊| 国产精品稀缺呦系列在线| 一区二区三区视频在线播放| 欧美激情一区二区| 亚洲欧洲综合另类| 欧美va亚洲va国产综合| 雨宫琴音一区二区在线| 久久青草福利网站| 黄色亚洲精品| 久久频这里精品99香蕉| 国模精品一区二区三区| 久久黄金**| 国产一区二区毛片| 久久精品一区蜜桃臀影院 | 亚洲视频中文| 欧美日韩专区| 亚洲视频网站在线观看| 欧美天堂亚洲电影院在线播放| 99热在线精品观看| 欧美日韩在线精品| 亚洲视频在线观看免费| 国产精品高潮在线| 亚洲性视频网址| 国产精品一区亚洲| 欧美在线视频免费| 黄色综合网站| 美女免费视频一区| 亚洲激情偷拍| 欧美伦理a级免费电影| 一区二区三区日韩欧美精品| 欧美视频在线观看免费网址| 亚洲一区二区免费看| 国产精品一区=区| 香蕉久久夜色精品国产| 国产一级揄自揄精品视频| 久久久99国产精品免费| 一区精品久久| 欧美国产高潮xxxx1819| av成人老司机| 国产精品二区在线| 久久成人综合网| 亚洲观看高清完整版在线观看| 欧美大片一区| 宅男66日本亚洲欧美视频| 国产精品捆绑调教| 久久国产精品久久久久久电车| 一区在线播放| 欧美久久精品午夜青青大伊人| 一区二区av| 国产美女精品视频| 美女精品网站| av成人国产| 国产婷婷97碰碰久久人人蜜臀| 美女视频一区免费观看| 99成人在线| 国产精品午夜久久| 蜜桃av综合| 在线综合亚洲| 狠狠干综合网| 欧美视频日韩| 久久久久久久精| 日韩视频永久免费观看| 国产视频自拍一区| 欧美高清视频免费观看| 亚洲一区免费| 亚洲第一黄色| 国产精品久久看| 欧美bbbxxxxx| 午夜精品久久久久久久| 亚洲激情欧美激情| 国产精品视频午夜| 免费高清在线一区| 亚洲欧美美女| 亚洲狠狠丁香婷婷综合久久久| 国产精品av久久久久久麻豆网| 久久久久久自在自线| 正在播放欧美视频| 在线播放国产一区中文字幕剧情欧美| 欧美日韩精品欧美日韩精品| 久久久精品动漫| 亚洲永久免费观看| 亚洲国产毛片完整版 | 另类国产ts人妖高潮视频| 亚洲一区不卡| 91久久精品视频| 国产一区二区三区高清播放| 欧美欧美午夜aⅴ在线观看| 久久精品观看| 亚洲小说欧美另类婷婷| 亚洲国产影院| 韩国女主播一区| 国产精品美女主播| 欧美国产视频在线观看| 欧美中文字幕不卡| 一区二区三区国产在线| 亚洲成人直播| 国产亚洲高清视频| 国产精品大片免费观看| 欧美国产日韩视频| 久久久久久亚洲综合影院红桃| 亚洲图中文字幕| 亚洲精品免费在线播放| 精品96久久久久久中文字幕无| 国产精品久久久久7777婷婷| 欧美高清一区二区| 久久久午夜精品| 久久成人人人人精品欧| 亚洲一区在线免费观看| 一本色道久久综合狠狠躁篇的优点 | 亚洲一区二区三区乱码aⅴ| 亚洲激情在线激情| 伊人久久男人天堂| 国内精品久久久久影院优| 国产精品久久午夜| 欧美色123| 欧美日韩18| 欧美国产视频在线观看| 久久中文字幕一区二区三区| 欧美一区二区三区在线看 | 亚洲午夜激情| 一区二区三区四区国产精品| 亚洲另类在线视频| 亚洲精品中文字幕在线| 亚洲国产一区二区视频| 在线播放国产一区中文字幕剧情欧美| 国户精品久久久久久久久久久不卡 | 亚洲毛片在线| 亚洲日韩欧美一区二区在线| 亚洲国产一区视频| 亚洲国产精品成人| 亚洲国产一区二区视频| 亚洲国产欧美一区二区三区久久| 在线国产亚洲欧美| 亚洲福利视频一区二区| 狠狠爱成人网| 激情久久久久久久| 伊人婷婷久久| 亚洲国产精品www| 亚洲国产精品久久久久婷婷884| 在线欧美三区| 亚洲国产成人精品久久|