项目中使用了 feign 作为 http 请求工具 . feign 自带的 http 客户端是 HttpURLConnection , 没有连接池功能 , 可配置能力差 , 因此通常会使用更强大的 OkHttp 作为底层的客户端实现 , 然后很多时候会发现对于 OkHttp 的自定义配置均会失效 , 这里记录下解决方案
先演示下通常是怎么配置的, 首先引入依赖
1 2 3 4 5
| <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-core</artifactId> <version>11.8</version> </dependency>
|
再修改Feign配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Configuration @ConditionalOnClass(Feign.class) @AutoConfigureBefore(FeignAutoConfiguration.class) public class FeignConfig { @Bean public Contract feignContract() { return new feign.Contract.Default(); }
@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 客户端
1 2 3 4
| feign: okhttp: enabled: true
|
到这里通常就结束了, 网上许多文章也是如此说明 , 可是当实际需求来时 , 比如请求时增加一个通用 header ,在给这个注入的 Okhttp 增加拦截器时发现实际请求并未生效.
定位问题
可以将服务根日志级别调整为 debug , 然后按照 [文章](真实案例:Feign切换client到okhttp无法生效,被老大骂得有点慌 - 简书) 进行调试 ,
会发现 OkHttp 的配置不符合运行条件 , 因此实际使用的还是默认配置
继续查看 FeignAutoConfiguration
这个配置类的细节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @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 { }
}
|
问题就出在这里 @ConditionalOnMissingBean({okhttp3.OkHttpClient.class})
即只有当容器中没有OkHttpClient的实例时 , 才会运行 . 而我们需要的就是注入了自定义 OkHttp , 因此只能自己实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Configuration @ConditionalOnClass(Feign.class) @AutoConfigureAfter(FeignAutoConfiguration.class) public class OkHttpFeignConfiguration {
@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) { return new OkHttpClient.Builder() .connectTimeout(8, TimeUnit.SECONDS) .readTimeout(8,TimeUnit.SECONDS) .writeTimeout(12,TimeUnit.SECONDS) .addInterceptor(new HeaderInterceptor()) .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), new TrustAllManager()) .hostnameVerifier(SSLSocketClient.getHostnameVerifier()) .build(); } }
|
当实际运行时 , 我们会发现已经生效 .