使用HttpClient和OkHttp
在Feign中,Client是一個非常重要的組件,F(xiàn)eign最終發(fā)送Request請求以及接收Response響應(yīng)都是由Client組件來完成的。Client在Feign源碼中是一個接口,在默認(rèn)情況下,Client的實現(xiàn)類是Client.Default。Client.Default是由HttpURLConnection來實現(xiàn)網(wǎng)絡(luò)請求的。另外,Client還支持HttpClient和OkHttp來進(jìn)行網(wǎng)絡(luò)請求。
首先查看FeignRibbonClient的自動配置類FeignRibbonClientAutoConfiguration,該類在程序啟動的時候注入一些Bean,其中注入了一個BeanName為feignClient的Client類型的Bean。在省缺配置BeanName為FeignClient的Bean的情況下,會自動注入Client.Default這個對象,跟蹤C(jī)lient.Default源碼,Client.Default使用的網(wǎng)絡(luò)請求框架是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); } ...... //代碼省略 } |
這種情況下,由于缺乏連接池的支持,在達(dá)到一定流量的后服務(wù)肯定會出問題 。
使用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注解可知,這個配置可以不寫,因為在默認(rèn)情況下就為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作為網(wǎng)絡(luò)請求框架,則只需要在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,默認(rèn)2000 max-connections: 200 #線程池最大連接數(shù) okhttp: enabled: true |
經(jīng)過上面設(shè)置已經(jīng)可以使用okhttp了,因為在FeignAutoConfiguration中已實現(xiàn)自動裝配
如果需要對okhttp做更精細(xì)的參數(shù)設(shè)置,那需要自定義okhttp的實現(xiàn),可以模仿上圖中的實現(xiàn)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/u010277958/article/details/88730889