0%

OpenFeign集成OkHttp

OpenFeign集成OkHttp

OpenFeign本质是HTTP来进行服务调用的,也就是需要集成一个Http客户端。

使用的是Client接口来进行请求的

1
2
3
4
5
6
public interface Client {

// request是封装的请求方式、参数、返回值类型
// options 是连接超时、读取超时等的配置项
Response execute(Request request, Options options) throws IOException;
}

默认是HttpURLConnection方式,也就是jdk中提供的最原始的那个

1
2
3
4
5
6
7
8
public static class Default implements Client {

@Override
public Response execute(Request request, Options options) throws IOException {
HttpURLConnection connection = convertAndSend(request, options);
return convertResponse(connection).toBuilder().request(request).build();
}
}

HTTP连接需要进行TCP三次握手,是一个比较耗时的操作,一般我们不直接使用HttpURLConnection,而是使用HttpClient/okHttp等支持连接池的客户端工具,以Feign集成OkHttp为例

添加依赖

1
2
3
4
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>

其包内有一个Client的实现类OkHttpClient,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public final class OkHttpClient implements Client {

@Override
public feign.Response execute(feign.Request input, feign.Request.Options options)
throws IOException {
okhttp3.OkHttpClient requestScoped;
if (delegate.connectTimeoutMillis() != options.connectTimeoutMillis()
|| delegate.readTimeoutMillis() != options.readTimeoutMillis()) {
requestScoped = delegate.newBuilder()
.connectTimeout(options.connectTimeoutMillis(), TimeUnit.MILLISECONDS)
.readTimeout(options.readTimeoutMillis(), TimeUnit.MILLISECONDS)
.followRedirects(options.isFollowRedirects())
.build();
} else {
requestScoped = delegate;
}
Request request = toOkHttpRequest(input);
Response response = requestScoped.newCall(request).execute();
return toFeignResponse(response, input).toBuilder().request(input).build();
}
}

配置连接池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

@Configuration
public class OkHttpConfig {
/**
* 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 X509TrustManager x509TrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
}

@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
}

@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 | KeyManagementException e) {
e.printStackTrace();
}
return null;
}

/**
* 连接池配置
*
* @return 连接池
*/
@Bean
public ConnectionPool pool() {
// 最大连接数、连接存活时间、存活时间单位(分钟)
return new ConnectionPool(200, 5, TimeUnit.MINUTES);
}

/**
* 信任所有主机名
*
* @return 主机名校验
*/
@Bean
public HostnameVerifier hostnameVerifier() {
return (s, sslSession) -> true;
}
}

yml配置

要开启OkHttp ,还需要在YML 中添加开启配置项,默认是关闭的

1
2
3
feign:
okhttp:
enabled: true

至于为什么需要配这个,看一下FeignAutoConfiguration中装配OkHttp的条件

1
2
3
4
5
6
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
@ConditionalOnProperty("feign.okhttp.enabled")
protected static class OkHttpFeignConfiguration

欢迎关注我的其它发布渠道