來源: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開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555171.html
標籤:其他
上一篇:Scala簡介和安裝
下一篇:返回列表
