好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Feign 使用HttpClient和OkHttp方式

使用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

查看更多关于Feign 使用HttpClient和OkHttp方式的详细内容...

  阅读:43次