以下情况都是对于spring-boot版本是1.5.14,如果是2.*可能会有不同
看书上
《Spring Cloud微服务:入门、实战与进阶.wx》5.2有介绍
《重新定义Spring Cloud实战》4.3.1
都介绍了feign整合了okhttp可以提升性能,目前公司在压测,发现feign自带的Client比较慢,于是考虑替换为okhttp的client,原因是feign默认使用的是JDK原生的URLConnection发送HTTP 请求,没有连接池, 但是对每个地址会保持 一个长连接, 即利用 HTTP 的 persistence connection。
初步配置
按书上说的,配置文件加上
feign:
okhttp:
enabled: true
httpclient:
enabled: false
同时引入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
最后加入配置类
package com.feiynn.study.springcloud.consumer.config;
import feign.Feign;
import okhttp3.ConnectionPool;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.netflix.feign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
/**
* @author dean
*/
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
public okhttp3.OkHttpClient okHttpClient() {
return new okhttp3.OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool())
.build();
}
}
看起来大公告成,然后需要测试一下。不过如何知道okhttp是否生效了呢,因为压测的cpu主要耗费在feign.Client$Default.converResponse(),也就是feign包下面的Client类里面的内部类Default的converResponse()方法,converResponse()方法又被Default类实现的接口实现方法execute()调用,那么在execute()方法内部打一个断点,然后在Default类的接口Client的okhttp实现类OkHttpClient的execute()方法内部打一个断点,然后随便执行一个feign调用,看断点是进入的哪个方法,就知道是否生效了。试验结果,确实走的OkHttpClient类,那么目前看起来一切安好。
验证超时配置
由于以前工程中配置了
feign:
okhttp:
enabled: true
httpclient:
enabled: false
client:
config:
default:
connectTimeout: 2000
readTimeout: 2000
不确定超时时间是由上面配置决定还是由FeignOkHttpConfig 里面的超时时间确定,于是进行了一番测试,发现FeignOkHttpConfig 里面的配置无效,为什么会无效呢?在FeignOkHttpConfig 方法里面打了断点,项目启动确实会进入,说明配置类应该生效了,带着疑问看了下类里面配置了@AutoConfigureBefore(FeignAutoConfiguration.class),于是看了下FeignAutoConfiguration的源码,里面有一段
@Configuration
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
@ConditionalOnProperty(value = "feign.okhttp.enabled")
protected static class OkHttpFeignConfiguration {
在这个类的方法里面打了断点,结果发现启动的时候根本就不进入,说明根本没有生效,为什么没有生效呢,把日志级别改为debug,打印的装配信息里面,说了OkHttpFeignConfiguration 没有装配成功,原因之一就是@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer"),因为要使用ribbon,这个类肯定会被依赖的,那么说明okhttp应该还有其他的config类,后面又找到了一个配置类OkHttpFeignLoadBalancedConfiguration,这也证明了为什么不配置自定义的FeignOkHttpConfig ,feign使用okhttp也生效了,因为OkHttpFeignLoadBalancedConfiguration也会注入okhttp3.OkHttpClient
最终方案
没有时间去探究为什么自定义的FeignOkHttpConfig里面配置的超时时间为什么不生效,既然配置文件的超时时间是生效的,且OkHttpFeignLoadBalancedConfiguration注入的okhttp3.OkHttpClient也是使用了链接池的,那么自定义FeignOkHttpConfig也没有存在的必要了,最终去掉这个类,超时时间由配置文件配置,整合到此结束,满足目前场景需要。