Feign-使用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. public static class Default implements Client {
  2. private final SSLSocketFactory sslContextFactory;
  3. private final HostnameVerifier hostnameVerifier;
  4. public Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
  5. this.sslContextFactory = sslContextFactory;
  6. this.hostnameVerifier = hostnameVerifier;
  7. }
  8. public Response execute(Request request, Options options) throws IOException {
  9. HttpURLConnection connection = this.convertAndSend(request, options);
  10. return this.convertResponse(connection, request);
  11. }
  12. ...... //代码省略
  13. }

        这种情况下,由于缺乏连接池的支持,在达到一定流量的后服务肯定会出问题 。    

使用HttpClient

        那么如何在Feign中使用HttpClient的框架呢?我们查看FeignAutoConfiguration.HttpClientFeignConfiguration的源码:


 
 
   
   
   
   
  1. @Configuration
  2. @ConditionalOnClass({ApacheHttpClient.class})
  3. @ConditionalOnMissingClass({"com.netflix.loadbalancer.ILoadBalancer"})
  4. @ConditionalOnMissingBean({CloseableHttpClient.class})
  5. @ConditionalOnProperty(
  6. value = {"feign.httpclient.enabled"},
  7. matchIfMissing = true
  8. )
  9. protected static class HttpClientFeignConfiguration {
  10. private final Timer connectionManagerTimer = new Timer( "FeignApacheHttpClientConfiguration.connectionManagerTimer", true);
  11. @Autowired(
  12. required = false
  13. )
  14. private RegistryBuilder registryBuilder;
  15. private CloseableHttpClient httpClient;
  16. protected HttpClientFeignConfiguration() {
  17. }
  18. @Bean
  19. @ConditionalOnMissingBean({HttpClientConnectionManager.class})
  20. public HttpClientConnectionManager connectionManager(ApacheHttpClientConnectionManagerFactory connectionManagerFactory, FeignHttpClientProperties httpClientProperties) {
  21. final HttpClientConnectionManager connectionManager = connectionManagerFactory.newConnectionManager(httpClientProperties.isDisableSslValidation(), httpClientProperties.getMaxConnections(), httpClientProperties.getMaxConnectionsPerRoute(), httpClientProperties.getTimeToLive(), httpClientProperties.getTimeToLiveUnit(), this.registryBuilder);
  22. this.connectionManagerTimer.schedule(new TimerTask() {
  23. public void run() {
  24. connectionManager.closeExpiredConnections();
  25. }
  26. }, 30000L, (long)httpClientProperties.getConnectionTimerRepeat());
  27. return connectionManager;
  28. }
  29. @Bean
  30. public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory, HttpClientConnectionManager httpClientConnectionManager, FeignHttpClientProperties httpClientProperties) {
  31. RequestConfig defaultRequestConfig = RequestConfig.custom().setConnectTimeout(httpClientProperties.getConnectionTimeout()).setRedirectsEnabled(httpClientProperties.isFollowRedirects()).build();
  32. this.httpClient = httpClientFactory.createBuilder().setConnectionManager(httpClientConnectionManager).setDefaultRequestConfig(defaultRequestConfig).build();
  33. return this.httpClient;
  34. }
  35. @Bean
  36. @ConditionalOnMissingBean({Client.class})
  37. public Client feignClient(HttpClient httpClient) {
  38. return new ApacheHttpClient(httpClient);
  39. }
  40. @PreDestroy
  41. public void destroy() throws Exception {
  42. this.connectionManagerTimer.cancel();
  43. if ( this.httpClient != null) {
  44. this.httpClient.close();
  45. }
  46. }
  47. }

        从代码@ConditionalOnClass({ApacheHttpClient.class})注解可知,只需要在pom文件上加上HttpClient依赖即可。另外需要在配置文件中配置feign.httpclient.enabled为true,从@ConditionalOnProperty注解可知,这个配置可以不写,因为在默认情况下就为true:


 
 
   
   
   
   
  1. <dependency>
  2. <groupId>io.github.openfeign groupId>
  3. <artifactId>feign-httpclient artifactId>
  4. <version>9.4.0 version>
  5. dependency>

 

使用OkHttp

       查看FeignAutoConfiguration.HttpClientFeignConfiguration的源码:


 
 
   
   
   
   
  1. @Configuration
  2. @ConditionalOnClass({OkHttpClient.class})
  3. @ConditionalOnMissingClass({"com.netflix.loadbalancer.ILoadBalancer"})
  4. @ConditionalOnMissingBean({okhttp3.OkHttpClient.class})
  5. @ConditionalOnProperty({"feign.okhttp.enabled"})
  6. protected static class OkHttpFeignConfiguration {
  7. private okhttp3.OkHttpClient okHttpClient;
  8. protected OkHttpFeignConfiguration() {
  9. }
  10. @Bean
  11. @ConditionalOnMissingBean({ConnectionPool.class})
  12. public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties, OkHttpClientConnectionPoolFactory connectionPoolFactory) {
  13. Integer maxTotalConnections = httpClientProperties.getMaxConnections();
  14. Long timeToLive = httpClientProperties.getTimeToLive();
  15. TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
  16. return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
  17. }
  18. @Bean
  19. public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
  20. Boolean followRedirects = httpClientProperties.isFollowRedirects();
  21. Integer connectTimeout = httpClientProperties.getConnectionTimeout();
  22. Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
  23. this.okHttpClient = httpClientFactory.createBuilder(disableSslValidation).connectTimeout((long)connectTimeout, TimeUnit.MILLISECONDS).followRedirects(followRedirects).connectionPool(connectionPool).build();
  24. return this.okHttpClient;
  25. }
  26. @PreDestroy
  27. public void destroy() {
  28. if ( this.okHttpClient != null) {
  29. this.okHttpClient.dispatcher().executorService().shutdown();
  30. this.okHttpClient.connectionPool().evictAll();
  31. }
  32. }
  33. @Bean
  34. @ConditionalOnMissingBean({Client.class})
  35. public Client feignClient(okhttp3.OkHttpClient client) {
  36. return new OkHttpClient(client);
  37. }
  38. }

       同理,如果想要在Feign中使用OkHttp作为网络请求框架,则只需要在pom文件中加上feign-okhttp的依赖,代码如下:


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

 

你可能感兴趣的:(微服务)