Spring Cloud 微服务之间的调用采用 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;
}
}