使用HttpClient和OkHttp
在Feign中,Client是一个非常重要的组件,Feign最终发送Request请求以及接收Response响应都是由Client组件来完成的。Client在Feign源码中是一个接口,在默认情况下,Client的实现类是Client.Default。Client.Default是由HttpURLConnection来实现网络请求的。另外,Client还支持HttpClient和OkHttp来进行网络请求。
首先查看FeignRibbonClient的自动配置类FeignRibbonClientAutoConfiguration,该类在程序启动的时候注入一些Bean,其中注入了一个BeanName为feignClient的Client类型的Bean。在省缺配置BeanName为FeignClient的Bean的情况下,会自动注入Client.Default这个对象,跟踪Client.Default源码,Client.Default使用的网络请求框架是HttpURLConnection,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public static class Default implements Client {
private final SSLSocketFactory sslContextFactory;
private final HostnameVerifier hostnameVerifier;
public Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
this .sslContextFactory = sslContextFactory;
this .hostnameVerifier = hostnameVerifier;
}
public Response execute(Request request, Options options) throws IOException {
HttpURLConnection connection = this .convertAndSend(request, options);
return this .convertResponse(connection, request);
}
...... //代码省略
}
|
这种情况下,由于缺乏连接池的支持,在达到一定流量的后服务肯定会出问题 。
使用HttpClient
那么如何在Feign中使用HttpClient的框架呢?我们查看FeignAutoConfiguration.HttpClientFeignConfiguration的源码:
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
|
@Configuration
@ConditionalOnClass ({ApacheHttpClient. class })
@ConditionalOnMissingClass ({ "com.netflix.loadbalancer.ILoadBalancer" })
@ConditionalOnMissingBean ({CloseableHttpClient. class })
@ConditionalOnProperty (
value = { "feign.httpclient.enabled" },
matchIfMissing = true
)
protected static class HttpClientFeignConfiguration {
private final Timer connectionManagerTimer = new Timer( "FeignApacheHttpClientConfiguration.connectionManagerTimer" , true );
@Autowired (
required = false
)
private RegistryBuilder registryBuilder;
private CloseableHttpClient httpClient;
protected HttpClientFeignConfiguration() {
}
@Bean
@ConditionalOnMissingBean ({HttpClientConnectionManager. class })
public HttpClientConnectionManager connectionManager(ApacheHttpClientConnectionManagerFactory connectionManagerFactory, FeignHttpClientProperties httpClientProperties) {
final HttpClientConnectionManager connectionManager = connectionManagerFactory.newConnectionManager(httpClientProperties.isDisableSslValidation(), httpClientProperties.getMaxConnections(), httpClientProperties.getMaxConnectionsPerRoute(), httpClientProperties.getTimeToLive(), httpClientProperties.getTimeToLiveUnit(), this .registryBuilder);
this .connectionManagerTimer.schedule( new TimerTask() {
public void run() {
connectionManager.closeExpiredConnections();
}
}, 30000L, ( long )httpClientProperties.getConnectionTimerRepeat());
return connectionManager;
}
@Bean
public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory, HttpClientConnectionManager httpClientConnectionManager, FeignHttpClientProperties httpClientProperties) {
RequestConfig defaultRequestConfig = RequestConfig.custom().setConnectTimeout(httpClientProperties.getConnectionTimeout()).setRedirectsEnabled(httpClientProperties.isFollowRedirects()).build();
this .httpClient = httpClientFactory.createBuilder().setConnectionManager(httpClientConnectionManager).setDefaultRequestConfig(defaultRequestConfig).build();
return this .httpClient;
}
@Bean
@ConditionalOnMissingBean ({Client. class })
public Client feignClient(HttpClient httpClient) {
return new ApacheHttpClient(httpClient);
}
@PreDestroy
public void destroy() throws Exception {
this .connectionManagerTimer.cancel();
if ( this .httpClient != null ) {
this .httpClient.close();
}
}
}
|
从代码@ConditionalOnClass({ApacheHttpClient.class})注解可知,只需要在pom文件上加上HttpClient依赖即可。另外需要在配置文件中配置feign.httpclient.enabled为true,从@ConditionalOnProperty注解可知,这个配置可以不写,因为在默认情况下就为true:
1
2
3
4
5
|
< dependency >
< groupId >io.github.openfeign</ groupId >
< artifactId >feign-httpclient</ artifactId >
< version >9.4.0</ version >
</ dependency >
|
使用OkHttp
查看FeignAutoConfiguration.HttpClientFeignConfiguration的源码:
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
|
@Configuration
@ConditionalOnClass ({OkHttpClient. class })
@ConditionalOnMissingClass ({ "com.netflix.loadbalancer.ILoadBalancer" })
@ConditionalOnMissingBean ({okhttp3.OkHttpClient. class })
@ConditionalOnProperty ({ "feign.okhttp.enabled" })
protected static class OkHttpFeignConfiguration {
private okhttp3.OkHttpClient okHttpClient;
protected OkHttpFeignConfiguration() {
}
@Bean
@ConditionalOnMissingBean ({ConnectionPool. class })
public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties, OkHttpClientConnectionPoolFactory connectionPoolFactory) {
Integer maxTotalConnections = httpClientProperties.getMaxConnections();
Long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
}
@Bean
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
Boolean followRedirects = httpClientProperties.isFollowRedirects();
Integer connectTimeout = httpClientProperties.getConnectionTimeout();
Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
this .okHttpClient = httpClientFactory.createBuilder(disableSslValidation).connectTimeout(( long )connectTimeout, TimeUnit.MILLISECONDS).followRedirects(followRedirects).connectionPool(connectionPool).build();
return this .okHttpClient;
}
@PreDestroy
public void destroy() {
if ( this .okHttpClient != null ) {
this .okHttpClient.dispatcher().executorService().shutdown();
this .okHttpClient.connectionPool().evictAll();
}
}
@Bean
@ConditionalOnMissingBean ({Client. class })
public Client feignClient(okhttp3.OkHttpClient client) {
return new OkHttpClient(client);
}
}
|
同理,如果想要在Feign中使用OkHttp作为网络请求框架,则只需要在pom文件中加上feign-okhttp的依赖,代码如下:
1
2
3
4
5
|
< dependency >
< groupId >io.github.openfeign</ groupId >
< artifactId >feign-okhttp</ artifactId >
< version >10.2.0</ version >
</ dependency >
|
OpenFeign替换为OkHttp
pom中引入feign-okhttp
1
2
3
4
|
< dependency >
< groupId >io.github.openfeign</ groupId >
< artifactId >feign-okhttp</ artifactId >
</ dependency >
|
在application.yml中配置okhttp
1
2
3
4
5
6
|
feign:
httpclient:
connection-timeout: 2000 #单位ms,默认2000
max-connections: 200 #线程池最大连接数
okhttp:
enabled: true
|
经过上面设置已经可以使用okhttp了,因为在FeignAutoConfiguration中已实现自动装配
如果需要对okhttp做更精细的参数设置,那需要自定义okhttp的实现,可以模仿上图中的实现
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/u010277958/article/details/88730889