真實案例:Feign 切換 okhttp 無法生效,被老大罵的有點慌!

来源:https://www.cnblogs.com/javastack/archive/2023/06/14/17479522.html
-Advertisement-
Play Games

來源:https://www.cnblogs.com/mufeng3421/p/11442412.html 提示:如果只看如何解決問題,請看文章的末尾如何解決這個問題 ## 1. 場景描述 最近項目中使用了feign當做http請求工具來使用、相對於httpclient、resttemplate來說 ...


來源:https://www.cnblogs.com/mufeng3421/p/11442412.html

提示:如果只看如何解決問題,請看文章的末尾如何解決這個問題

1. 場景描述

最近項目中使用了feign當做http請求工具來使用、相對於httpclient、resttemplate來說,fegin用起來方便很多。然後項目有httptrace的需求,需要輸出請求日誌。

所以就開啟了feign自己的日誌,發現它自帶的日誌是debug級別才能列印。而且是逐行列印的,看日誌非常的不方便。所以需要輸出json格式的日誌最好。

2.解決步驟

2.1 引入feign依賴

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${自行選擇適合項目的版本}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

這裡使用了spring-cloud-openfeing來避免自己手工實現feign的註入,用法上和feign一樣

推薦一個開源免費的 Spring Boot 實戰項目:

https://github.com/javastacks/spring-boot-best-practice

2.2 配置feign

在入口類上添加 @EnableFeignClients 註解

@SpringBootApplication
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

使用feing自己的Contract,方便使用feign自己的註解來聲明http介面。這裡使用了一個配置類

@Configuration
public class FeignConfig {
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }
}

2.3 聲明介面

只需要聲明一個帶有@FeignClient註解的介面,就聲明好了一個Feign的http請求介面

@FeignClient(name = "accessPlatform", url = "${url.access-platform}")
public interface AccessPlatformFeignClient {
    @RequestLine("GET /access-platform/resource")
    List<AccessResource> queryResourceList(@QueryMap Map<String, Object> query);
}

3.切換Feign的客戶端為OkHttp

由於feign自帶的http客戶端實現是HttpURLConnection,沒有連接池功能,可配置能力也比較差,因此我們使用okhttp作為底層的http客戶端的具體實現。

3.1 引入okhttp的依賴

 <dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>${feign-okhttp.version}</version>
</dependency>

3.2 修改之前的FeignConfig配置類

問題就出在這裡、不過先不急,我們繼續

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignConfig {
    // 註入feignContract
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

    // 註入自定義的okHttpClient
    @Bean
    public okhttp3.OkHttpClient okHttpClient(){
        return new okhttp3.OkHttpClient.Builder()
            .readTimeout(60, TimeUnit.SECONDS)
            .connectTimeout(60, TimeUnit.SECONDS)
            .writeTimeout(120, TimeUnit.SECONDS)
            .connectionPool(new ConnectionPool())
            .build();
    }
}

開啟okhttp作為feign的客戶端

# application.yml
feign:
    okhttp:
        enabled: true

一切完美、網上的許多博客也都是這麼寫的。然後它們告訴你已經配置完了?呵呵,你們到底自己試過沒有??

3.3 試著請求一下

當然這裡出問題了,發出的請求並非來自okhttp,還是預設的JDK的HttpURLConnection,問題出在哪裡呢?接著看

4.找出問題所在

我懷疑是feing在註入配置的時候,根本就沒有運行關於okhttp的配置

4.1 查看服務啟動時feign配置過程

1.將服務根日誌級別調整為debug級別

logging:
    level:
    	root: debug

2.啟動服務、查看控制台輸出

控制台輸出

看到沒,okhttp的配置不符合配置運行條件。

3.查詢 FeignAutoConfiguration 這個配置類的細節

@Configuration
@ConditionalOnClass({Feign.class})
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {
		// .....其他的配置
  	@Configuration
    @ConditionalOnClass({OkHttpClient.class})
    @ConditionalOnMissingClass({"com.netflix.loadbalancer.ILoadBalancer"})
    @ConditionalOnMissingBean({okhttp3.OkHttpClient.class})
    @ConditionalOnProperty({"feign.okhttp.enabled"})
    protected static class OkHttpFeignConfiguration {
       // ...okhttp的配置
    }

  	// .....其他的配置
}

就是這個自動配置類搞的鬼、當我看到 @ConditionalOnMissingBean({okhttp3.OkHttpClient.class}) 這個註解時,我就明白了。
翻成白話就是,只有當容器中沒有OkHttpClient的實例時。他才會運行。如果在 FeignAutoConfiguration之前註入了我們自己定義的OkHttpClient實例,那不好意思,我不幹了?無不註入。

5.解決問題

既然自動配置不幹,那我們自己動手乾。拷貝 FeignAutoConfiguration 配置類中的配置過程,粘貼在FeignConfig配置類中手動註入feign的client。Ok!完美解決。

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureAfter(FeignAutoConfiguration.class)
public class FeignConfig {
//    private okhttp3.OkHttpClient okHttpClient;

    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

    @Bean
    @ConditionalOnMissingBean({Client.class})
    public Client feignClient(okhttp3.OkHttpClient client) {
        return new feign.okhttp.OkHttpClient(client);
    }

    @Bean
    @ConditionalOnMissingBean({ConnectionPool.class})
    public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties, OkHttpClientConnectionPoolFactory connectionPoolFactory) {
        Integer maxTotalConnections = httpClientProperties.getMaxConnections();
        Long timeToLive = httpClientProperties.getTimeToLive();
        TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
        return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
    }

    @Bean
    public OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
        Boolean followRedirects = httpClientProperties.isFollowRedirects();
        Integer connectTimeout = httpClientProperties.getConnectionTimeout();
        Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
        return httpClientFactory.createBuilder(disableSslValidation)
                .connectTimeout((long)connectTimeout, TimeUnit.MILLISECONDS)
                .followRedirects(followRedirects)
                .connectionPool(connectionPool)
                .addInterceptor(new OkHttpLogInterceptor()) // 自定義請求日誌攔截器
                .build();
    }
}

6.小結

如果你沒有耐心看完所有的過程的話。就記住一句話:用自己手動註入Feign的Client實現,來代替 Feign的自動配置所做的過程就好了。具體的配置請看第5點。

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2022最新版)

2.勁爆!Java 協程要來了。。。

3.Spring Boot 2.x 教程,太全了!

4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!

5.《Java開發手冊(嵩山版)》最新發佈,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Fork譯為拆分,Join譯為合併Fork/Join框架的思路是把一個非常巨大的任務,拆分成若然的小任務,再由小任務繼續拆解。直至達到一個相對合理的任務粒度。然後執行獲得結果,然後將這些小任務的結果彙總,生成大任務的結果,直至彙總成最初巨大任務的結果。如下圖: 紅色箭頭代表拆分子任務。綠色箭頭代表返 ...
  • 本文實現的功能主要是根據已知欄位值,給指定的名稱欄位賦上對應的值;整個處理的邏輯很簡單,就是通過判斷語句,判斷其他欄位值,然後給指定的欄位填上對應的值即可; 欄位統計界面如下圖所示: #腳本代碼如下 def updatefiles(ssssss): if(ssssss == 1): total="高 ...
  • ## 教程簡介 Aurelia 是一個用於 Web 和移動應用程式開發的現代開源 UI 框架。它允許您編寫乾凈、模塊化的 JavaScript。該框架遵循簡單的約定,並專註於 Web 標準。 [Aurelia入門教程](https://www.itbaoku.cn/tutorial/aurelia- ...
  • ## 教程簡介 Apache Tajo是Hadoop的開源分散式數據倉庫框架。塔霍最初由位於南韓的基於Hadoop的基礎設施公司Gruter開始。後來,Intel,Etsy,NASA,Cloudera,Hortonworks的專家也為該項目做出了貢獻。塔霍指北韓鴕鳥。在2014年3月,Tajo獲得了 ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
  • # 頁面預覽 ## 用戶認證 - 用戶登錄成功後都要進行身份認證,認證通過後才可以預約掛號。 - 認證過程:用戶填寫基本信息(姓名、證件類型、證件號碼和證件照片),提交平臺審核 - 用戶認證相關介面: (1)上傳證件圖片 (2)提交認證 (3)獲取認證信息 ### 提交認證 ![image-2023 ...
  • 轉載於:https://blog.csdn.net/weixin_40461281/article/details/122837923 RuoYi-Cloud-Plus 微服務通用許可權管理系統 重寫 RuoYi-Cloud 全方位升級(不相容原框架) 系統演示: 傳送門 分散式集群版本(功能一致) ...
  • # -- coding:utf-8 -- import geopandas as gpd import os from osgeo import ogr # shp 文件批量添加欄位 def addfeilds(filepath): for filename in os.listdir(filepa ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...