Spring 教程

Spring 笔记

spring cloud http 客户端连接使用高性能的 okhttp 连接池配置

Spring 笔记 Spring 笔记


Spring Cloud 微服务之间的调用采用 http 协议,它的 http 客户端支持 3 种形式,默认情况下,http 组件使用 JDK 的 HttpURLConnection,但是它比较低效,不支持连接池,每次请求都新建立连接,可以使用 apache 的 httpclient 或 square 公司开源的 okhttp client。

OkHttpClient 引入

Spring Cloud 的 http client 是 feign 层使用,ribbon 的 LoadBalancerFeignClient 拿到对应的 http client 使用。

maven 构建的项目中,在 pom.xml 引入:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

gradle 构建的项目中,在 build.gradle 引入:

compile group: 'io.github.openfeign', name: 'feign-okhttp'

feign-okhttp 这里可以不指定版本,它会根据 spring cloud dependencies 依赖导入相应版本。

配置 application.yml

feign 中使用 http client 的优先顺序可以查看源码 FeignRibbonClientAutoConfiguration 类,该类上的 @Import 注解上的 FeignLoadBalancedConfiguration 导入顺序就是优先顺序,笔者的版本示例如下:

@Import({ HttpClientFeignLoadBalancedConfiguration.class,
		OkHttpFeignLoadBalancedConfiguration.class,
		DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {
    ...
}

如上源代码中可以看出,它会优先适配 apache http client,然后 okhttp,最后是默认的 jdk http client。

根据源码逻辑可以得出,为了确保 okhttp 的使用,最好显性地禁止 apache http client(万一其他依赖导入 apache http client),application.yml 增加如下配置:

feign:
  httpclient:
    enabled: false
  okhttp:
    enabled: true

配置 OkHttpClient 连接池

okhttp 的优势之一是通过连接池,可以减少请求延迟。

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
public class OKHttpClientPoolConfig {

    @Bean
    public OkHttpClient okHttpClient() {

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //  设置连接超时
                .connectTimeout(5 * 1000, TimeUnit.MILLISECONDS)
                //  设置读取超时
                .readTimeout(5 * 1000, TimeUnit.MILLISECONDS)
                //  设置写入超时
                .writeTimeout(5 * 1000, TimeUnit.MILLISECONDS)
                //  设置连接失败重试
                .retryOnConnectionFailure(true)
                //  设置最大连接数 和 保持连接时间
                .connectionPool(new ConnectionPool(100, 30L, TimeUnit.SECONDS))
                .build();

        return okHttpClient;
    }

}