Feign 使用HttpClient和OkHttp方式

目录
  • 使用HttpClient和OkHttp
    • 使用HttpClient
    • 使用OkHttp
  • OpenFeign替换为OkHttp
    • pom中引入feign-okhttp
    • 在application.yml中配置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,代码如下:

 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的源码:

     @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:

 <dependency>     <groupId>io.github.openfeign</groupId>     <artifactId>feign-httpclient</artifactId>     <version>9.4.0</version> </dependency>

使用OkHttp

查看FeignAutoConfiguration.HttpClientFeignConfiguration的源码:

     @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的依赖,代码如下:

 <dependency>     <groupId>io.github.openfeign</groupId>     <artifactId>feign-okhttp</artifactId>     <version>10.2.0</version> </dependency>

OpenFeign替换为OkHttp

pom中引入feign-okhttp

 <dependency>     <groupId>io.github.openfeign</groupId>     <artifactId>feign-okhttp</artifactId> </dependency>

在application.yml中配置okhttp

 feign:   httpclient:     connection-timeout: 2000  #单位ms,默认2000     max-connections: 200 #线程池最大连接数   okhttp:     enabled: true

经过上面设置已经可以使用okhttp了,因为在FeignAutoConfiguration中已实现自动装配

Feign 使用HttpClient和OkHttp方式

如果需要对okhttp做更精细的参数设置,那需要自定义okhttp的实现,可以模仿上图中的实现

以上为个人经验,希望能给大家一个参考,也希望大家多多支持IIS7站长之家博文。

本站由小牛团队全力维护,小牛十年了,大家已经步入中年 。本站源码全部经过团队成员测试并调试,价格可能比其它网站略贵几元钱,不解释!
小牛资源 » Feign 使用HttpClient和OkHttp方式

发表评论

全站资源亲测可用,价格略高几元,不解释

立即查看 了解详情