解决Feign切换client到okhttp⽆法⽣效的坑(出现原因说明)提⽰:如果只看如何解决问题,请看⽂章的末尾如何解决这个问题
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⼀样
2.2 配置feign
在⼊⼝类上添加 @EnableFeignClients 注解
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
springmvc选择题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的客户端
# l
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({"comflix.loadbalancer.ILoadBalancer"})
@ConditionalOnMissingBean({okhttp3.OkHttpClient.class})
@ConditionalOnProperty({"abled"})
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 = MaxConnections();
Long timeToLive = TimeToLive();
TimeUnit ttlUnit = TimeToLiveUnit();
ate(maxTotalConnections, timeToLive, ttlUnit);
}
@Bean
public OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
Boolean followRedirects = httpClientProperties.isFollowRedirects();
Integer connectTimeout = ConnectionTimeout();
Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
ateBuilder(disableSslValidation)
.connectTimeout((long)connectTimeout, TimeUnit.MILLISECONDS)
.followRedirects(followRedirects)
.connectionPool(connectionPool)
.addInterceptor(new OkHttpLogInterceptor()) // ⾃定义请求⽇志
.build();
}
}
6.⼩结
如果你没有耐⼼看完所有的过程的话。就记住⼀句话:⽤⾃⼰⼿动注⼊Feign的Client实现,来代替 Feign的⾃动配置所做的过程就好了。
具体的配置请看第5点
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。如有错误或未考虑完全的地⽅,望不吝赐教。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论