以下情况都是对于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也没有存在的必要了,最终去掉这个类,超时时间由配置文件配置,整合到此结束,满足目前场景需要。