在之前文档中,可以了解到,Feign 是集成了其他HTTP 客户端框架进行请求发送。
实际发送请求是由Feign 中的Client
接口实现类去处理的,默认使用的是Defalut 类,该类使用的是HttpURLConnection
。
Client 接口只有一个execute 方法,该方法有两个参数:
public interface Client {
Response execute(Request var1, Options var2) throws IOException;
}
Default
是Client 接口的默认实现类,重写了execute 方法。
// 执行请求
public Response execute(Request request, Options options) throws IOException {
// 1. 处理请求
HttpURLConnection connection = this.convertAndSend(request, options);
// 2. 发送请求、处理响应
return this.convertResponse(connection, request);
}
可以看到Default 在发送请求时,实际使用的是HttpURLConnection
(JDK 提供的网络编程包)。
HttpURLConnection convertAndSend(Request request, Options options) throws IOException {
// 创建URL
URL url = new URL(request.url());
// 获取连接
HttpURLConnection connection = this.getConnection(url);
// https 处理
if (connection instanceof HttpsURLConnection) {
HttpsURLConnection sslCon = (HttpsURLConnection)connection;
if (this.sslContextFactory != null) {
sslCon.setSSLSocketFactory(this.sslContextFactory);
}
if (this.hostnameVerifier != null) {
sslCon.setHostnameVerifier(this.hostnameVerifier);
}
}
// 连接配置
connection.setConnectTimeout(options.connectTimeoutMillis());
connection.setReadTimeout(options.readTimeoutMillis());
connection.setAllowUserInteraction(false);
// 省略.....
return connection;
}
}
Proxied
类继承了Default,有一个 Proxy
属性,提供了代理服务器去访问的方式。
在Feign
的功能图中,可以看到 Feign 对其他HTTP 客户端框架的支持,比如常用的有Ok Http、Apache Http Client。
在HTTP 通信的过程中,建立连接是一个很复杂的过程,涉及到多个数据包的交换,很耗时间,而且HTTP连接需要3次握手和4次挥手开销都很大。
这时可以采用HTTP连接池
,节约大量的3次握手4次挥手时间,提升吞吐量。
默认的HttpURLConnection
是JDK自带的,并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。
HttpClient
相比传统JDK自带的HttpURLConnection,它封装了访问HTTP的请求头,参数,内容体,响应等等。它不仅使客户端发送HTTP请求变得容易,而且也方便了开发人员测试接口(基于HTTP协议的),既提高了开发的效率,又提高了代码的健壮性。另外高并发大量的请求网络的时候,也是用"连接池"
提升吞吐量。
OkHttp
作为后期之秀,功能和性能上,可能稍优于HttpClient
,但是几乎没多大区别,实际使用时,都是可以的,不过HttpClient
集成起来更方便。
直接添加okhttp
:
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-okhttpartifactId>
dependency>
可以看到当前使用的是3.14.9
版本:
在feign-okhttp-10.12.jar
中,提供了Client 的实现类,可以看到,执行请求时,使用的是OkHttp 中的API。
要开启OkHttp ,还需要在YML 中添加开启配置项,默认是关闭的:
feign:
okhttp:
enabled: true
然后重新启动程序,进入Debug 模式,可以看到最终请求是由OkHttp 发送,集成成功。
在配置Feign 的时候,可以看到httpclient
默认提供了配置项,但是OkHttp 并没有默认配置项。
在使用Spring 时,可以通过@Bean
声明这些配置,在实际项目中,应该把这些配置项写在配置类中。
@Configuration
public class OkHttpConfig {
/**
* 忽略证书校验
*
* @return 证书信任管理器
*/
@Bean
public X509TrustManager x509TrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
}
/**
* 信任所有 SSL 证书
*
* @return
*/
@Bean
public SSLSocketFactory sslSocketFactory() {
try {
TrustManager[] trustManagers = new TrustManager[]{x509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new SecureRandom());
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return null;
}
/**
* 连接池配置
*
* @return 连接池
*/
@Bean
public ConnectionPool pool() {
// 最大连接数、连接存活时间、存活时间单位(分钟)
return new ConnectionPool(200, 5, TimeUnit.MINUTES);
}
/**
* OkHttp 客户端配置
*
* @return OkHttp 客户端配
*/
@Bean
public OkHttpClient okHttpClient() {
return new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory(), x509TrustManager())
.hostnameVerifier(hostnameVerifier())
.retryOnConnectionFailure(false) //是否开启缓存
.connectionPool(pool()) //连接池
.connectTimeout(15L, TimeUnit.SECONDS) // 连接超时时间
.readTimeout(15L, TimeUnit.SECONDS) // 读取超时时间
.followRedirects(true) // 是否允许重定向
.build();
}
/**
* 信任所有主机名
*
* @return 主机名校验
*/
@Bean
public HostnameVerifier hostnameVerifier() {
return (s, sslSession) -> true;
}
}
启动项目,Dubug 到OkHttpClient,可以看到,配置生效,连接池配置成功。
最后使用Jemeter 简单测试下,可以看到使用连接池后,吞吐量明显提升。
使用HttpURLConnection:
使用Okhttp + 连接池: