当前位置:首页 > 服务端 > Feign使用okhttp的排坑之旅

Feign使用okhttp的排坑之旅

2022年11月08日 23:15:16服务端36

1、由于项目需要远程调用http请求,因此就想到了Feign,因为真的非常的方便,只需要定义一个接口就行。但是feign默认使用的JDK的URLHttpConnection,没有连接池效率不好,从Feign的自动配置类FeignAutoConfiguration中可以看到Feign除了默认的http客户端还支持okhttp和ApacheHttpClient,我这里选择了okhttp,它是有连接池的。

2、看看网络上大部分博客中是怎么使用okhttp的

1)、引入feign和okhttp的maven坐标

<dependencyManagement>
    <dependencies>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-dependencies</artifactId>
           <version>${spring-cloud.version}</version>
           <type>pom</type>
           <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

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

 2)、在配置文件中禁用默认的URLHttpConnection,启动okhttp

feign.httpclient.enabled=false
feign.okhttp.enabled=true

 3)、其实这个时候就可以使用okhttp了,但网络上大部分博客还写了一个自定义配置类,在其中实例化了一个okhttp3.OkHttpClient,就是这么一个配置类导致了大坑啊,有了它之后okhttp根本不会生效,不信咱们就是来试一下

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class OkHttpConfig {

    @Bean
    public okhttp3.OkHttpClient okHttpClient(){
        return new okhttp3.OkHttpClient.Builder()
                //设置连接超时
                .connectTimeout(10 , TimeUnit.SECONDS)
                //设置读超时
                .readTimeout(10 , TimeUnit.SECONDS)
                //设置写超时
                .writeTimeout(10 , TimeUnit.SECONDS)
                //是否自动重连
                .retryOnConnectionFailure(true)
                .connectionPool(new ConnectionPool(10 , 5L, TimeUnit.MINUTES))
                .build();
    }
}

上面这个配置类其实就是配置了一下okhttp的基本参数和连接池的基本参数

此时我们可以在配置文件中开始日志打印,看一下那些自动配置没有生效

debug=true

启动我们的项目可以在控制台搜索到如下日志输出

FeignAutoConfiguration.OkHttpFeignConfiguration:
      Did not match:
         - @ConditionalOnBean (types: okhttp3.OkHttpClient; SearchStrategy: all) found beans of type 'okhttp3.OkHttpClient' okHttpClient (OnBeanCondition)
      Matched:
         - @ConditionalOnClass found required class 'feign.okhttp.OkHttpClient'; @ConditionalOnMissingClass did not find unwanted class 'com.netflix.loadbalancer.ILoadBalancer' (OnClassCondition)
         - @ConditionalOnProperty (feign.okhttp.enabled) matched (OnPropertyCondition)

从日志中可以清楚的看到FeignAutoConfiguration.OkHttpFeignConfiguration没有匹配成功(Did not match),原因也很简单是因为容器中已经存在了okhttp3.OkHttpClient对象,我们去看看这个配置类的源码,其中类上标注了@ConditionalOnMissingBean(okhttp3.OkHttpClient.class),意思上当容器中不存在okhttp3.OkHttpClient对象时才生效,然后我们却在自定义的配置类中画蛇添足的实例化了一个该对象到容器中。

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(OkHttpClient.class)
	@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
	@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
	@ConditionalOnProperty("feign.okhttp.enabled")
	protected static class OkHttpFeignConfiguration {

		private okhttp3.OkHttpClient okHttpClient;

		@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(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);
		}

	}

4)、该如何处理才能使okhttp生效

 其中我们的自定义配置类中并没有做什么特别复杂的事情,仅仅是给okhttp3.OkHttpClient和它的连接池对象设置了几个参数罢了,看看上面OkHttpFeignConfiguration类中实例化的几个类对象,其中就包含了okhttp3.OkHttpClient和ConnectionPool,从代码中不难看出它们的参数值都是从FeignHttpClientProperties获取的,因此我们只需要在配置文件中配上feign.httpclient开头的相关配置就可以了生效了。如果我们的目的不仅仅是简单的修改几个参数值,比如需要在okhttp中添加拦截器Interceptor,这也非常简单,只需要写一个Interceptor的实现类,然后将OkHttpFeignConfiguration的内容完全复制一份到我们自定义的配置类中,并设置okhttp3.OkHttpClient的拦截器即可。

import okhttp3.Interceptor;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class MyOkhttpInterceptor implements Interceptor {

    Logger logger = LoggerFactory.getLogger(MyOkhttpInterceptor.class);

    @Override
    public Response intercept(Chain chain) throws IOException {
        logger.info("okhttp method:{}",chain.request().method());
        logger.info("okhttp request:{}",chain.request().body());
        return chain.proceed(chain.request());
    }
}

将自定义配置类中原有的内容去掉,复制一份OkHttpFeignConfiguration的代码做简单的修改,设置拦截器的代码如下

    @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(connectTimeout, TimeUnit.MILLISECONDS)
                .followRedirects(followRedirects).connectionPool(connectionPool)
                   //这里设置我们自定义的拦截器
                .addInterceptor(new MyOkhttpInterceptor())
                .build();
        return this.okHttpClient;
    }

  

3、最后上两张图,Feign的动态代理使用和处理流程

Feign使用okhttp的排坑之旅 _ JavaClub全栈架构师技术笔记

Feign使用okhttp的排坑之旅 _ JavaClub全栈架构师技术笔记 

作者:石楠烟斗的雾
来源链接:https://blog.csdn.net/ccf199201261/article/details/103547552

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/server/68575.html

标签: FeignHTTP
分享给朋友:

“Feign使用okhttp的排坑之旅” 的相关文章

springboot学习(三)——使用HttpMessageConverter进行http序列化和反序列化

springboot学习(三)——使用HttpMessageConverter进行http序列化和反序列化

以下内容,如有问题,烦请指出,谢谢! 对象的序列化/反序列化大家应该都比较熟悉:序列化就是将object转化为可以传输的二进制,反序列化就是将二进制转化为程序内部的对象。序列化/反序列化主要体现在程序I/O这个过程中,包括网络I/O和磁盘I/O。 那么什么是http...

Springboot 实现 Restful 服务,基于 HTTP / JSON 传输

Springboot 实现 Restful 服务,基于 HTTP / JSON 传输

“怎样的人生才是没有遗憾的人生?我的体会是:(1)拥有健康;(2)创造“难忘时刻”;(3)尽力做好自己,不必改变世界;...

SpringBoot系列——启用https

SpringBoot系列——启用https

  前言   有时候我们需要使用https安全协议,本文记录在SpringBoot项目启用https     生成证书   自签名证书   使用java jdk自带的生成SSL证书的工具keytool生成自己的证书   1、打开cmd...

基于HttpRunner,解析swagger数据,快速生成接口测试框架

基于HttpRunner,解析swagger数据,快速生成接口测试框架

  使用 HttpRunner 默认生成的项目是这样的   命令:httprunner --startproject  项目名称    so,根据这个项目的目录结构,使用python解析swagger接口参数,可以...

Warning: Mapping new ns http://schemas.android.com/repository/android/common/02 to old ns http://sch

我Flutter,在运行应用程序时,我在调试控制台中收到如下错误: Warning: Mapping new ns http://schemas.android.com/repository/android/common/02 to old ns...

python实现的json数据以HTTP GET,POST,PUT,DELETE方式页面请求

转自 http://blog.chinaunix.net/uid-26000296-id-4394470.html 一、JSON简介 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。...

SpringCloud服务调用之OpenFeign

SpringCloud服务调用之OpenFeign

     怎么使用? 注意:FeignClinet 是在消费段调用。Feign自带负载均衡配置项 1.导入pom <?xml version="1.0" e...

HTTP请求的完全过程

HTTP请求的完全过程

 HTTP请求的完全过程 1.1 浏览器根据域名解析IP地址        浏览器根据访问的域名找到其IP地址。DNS查找过程如下: 浏览器缓存:首先搜索浏览器自身的DNS缓存(缓存的...

优化--减少HTTP请求

优化--减少HTTP请求

一、 图片地图 (将几张图片合为一张,根据用户点击的位置发送不同请求,减少了图片的请求数量) 案例所在位置:http://stevesouders.com/hpws/imagemap.php   二、css精灵(和图片地图功能相似,都是将几张图...

.NET下使用HTTP请求的正确姿势

.NET下使用HTTP请求的正确姿势

来源:Lewis.Zou cnblogs.com/modestmt/p/7724821.html   一、前言   去年9月份的时候我看到过外国朋友关于.NET Framework下HttpClien...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。