完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题
作者:esunlang 发布时间:2023-07-03 11:27:25
事发地
原默认的Feign是使用URLConnector进行通信的,当换为okhttp时,直接引入包及配置以下内容根本不生效,还是走原生的。
feign:
okhttp:
enable: true
事件还原
创建项目并引入pom相关的依赖如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>``
启动类
@SpringBootApplication
@EnableFeignClients
public class Ch21OpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(Ch21OpenFeignApplication.class, args);
}
}
配置文件
bootstrap.yml,这里只配置是否使用相关的HTTP
logging:
level:
springcloud.service.HelloFeignService: debug
feign:
okhttp:
enable: true
httpclient:
enable: false
测试类
Controller
.`@RestController
public class HelloFeignController {
@Autowired
private HelloFeignService helloFeignService;
@RequestMapping(value = "/helloFeign",method = RequestMethod.GET)
public Object helloFeign(){
return helloFeignService.helloFeign();
}
}`
service
@FeignClient(name = "feign-client",url = "http://localhost:8761",fallback = FallbackService.class)
public interface HelloFeignService {
@RequestMapping(value = "/query/eureka-server",method = RequestMethod.GET)
String helloFeign();
}
案件还原
写好上述的配置与类后,开始DEBUG,下图是Controller的DEBUG入口:
进入代理类查看HTTPCLIENT使用的是哪一个
到下图时就要注意了,这才是进入使用client的入口
结果看下图:
参考
经过查找资料,有文章提到是自动配置类的问题FeignAutoConfiguration,文章参考:www.jb51.net/article/206294.htm文章提到,由于@ConditionalOnMissingBean({okhttp3.OkHttpClient.class})导致了无法注入OkHttpClient
个人猜测
在只添加依赖包时,还没有自行创建okhttp相关的BEAN时,结果如下与添加了创建okhttp时一样。
启动springboot项目时,BEAN容器化时机不同导致得不到想要的client,在启动项目时,org.springframework.cloud.openfeign.FeignAutoConfiguration这个配置类是执行后。在BEAN装载时看到BEAN一级缓存如下图,并没有OKHTTP相关的信息。
在这个自动装配类最下方有一段代码根本没有执行,所以从始到终都没有看到有okHttpClient
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient() {
return new OkHttpClient(this.okHttpClient);
}
当我在主类添加以下代码时,得到的bean如下:
注意:feignClient 这个bean 是一个loadBalancerFeignClient
@Bean
public okhttp3.OkHttpClient okHttpClient(){
return new okhttp3.OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool())
// .addInterceptor();
.build();
}
当我在主类再追加以下代码时,得到的bean如下:
注意:feignClient 这个bean,是我们要找的okhttp了
@Bean
@ConditionalOnMissingBean({Client.class})
public Client feignClient(okhttp3.OkHttpClient client) {
return new feign.okhttp.OkHttpClient(client);
}
真正的真相
这个要再多看下创建流程,从代码上分析,这时在有new feign.okhttp.OkHttpClient(client); 这一段代码,重新把okhttp注入后,才使得feignClient 名称对应的bean为okhttp。不防从以下代码进行分析:
LoadBalancerFeignClient 的来源
如下图,LoadBalancerFeignClient是继承了Client,进入实现类feign.Client.Default,这个类全程都只有使用HttpURLConnection,所以无论怎样都只能获取到的是默认的JDK里的http的client
所以这个类创建后要想使用okhttp,那么就只能重新创建把旧的bean冲掉,还好,在主类添加的@Bean创建的类正是在完成bean后再执行这里主类增加的@Bean创建的对象,所以最后加载过程中又会执行bean生命周期的finishBeanFactoryInitialization(beanFactory);
方法所在位置如下:
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
注意事项
在主类添加的方法用来创建okhttp时,方法名一定要写成下图的这样,不然创建不了feignClient这个bean。
不知道是否有其他方法。这个估计是与org.springframework.cloud.openfeign.FeignAutoConfiguration.OkHttpFeignConfiguration#feignClient有关,相当于创建的方法是一个重写的过程。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。
来源:https://blog.csdn.net/esunlang/article/details/113772887


猜你喜欢
- 直接看代码,注释都写清楚了public class MainActivity extends Activity { private
- 在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用。通常我们的代码会这样实现。public class Sa
- 简介API Gateway,时系统的唯一对外的入口,介于客户端和服务端之间的中间层,处理非业务功能,提供路由请求,鉴权,监控,缓存,限流等功
- 本文实例为大家分享了Java NIO实战之多人聊天室的具体代码,供大家参考,具体内容如下NIO服务端public class NioServ
- 方法调用在程序运行时,进行方法调用是最普遍,最频繁的操作方法调用不等于方法执行:方法调用阶段唯一的任务就是确定被调用的方法版本,即调用哪一个
- 本文实例为大家分享了C#实现简单打字小游戏的具体代码,供大家参考,具体内容如下using System;using System.Colle
- 本文实现android系统照相机的调用来拍照项目的布局相当简单,只有一个Button:<RelativeLayout xmlns:an
- ContentProvider是内容提供者,可以跨进程提供数据。大家都知道,ContentProvider的启动,是在Application
- 前言上一篇:微服务网关Zuul上文中,我们介绍了微服务网关Zuul,Zuul 是 Netflix 公司开源的产品,被称为第一代网关,也是 S
- 前几天有个客户在系统上写了一段html语句,打开页面就显示一张炒鸡大的图片,影响美观。后来仔细想想,幸亏注入的仅仅是html语句,知道严重性
- 本文为大家分享了Unity3D实现虚拟按钮控制人物移动的具体代码,供大家参考,具体内容如下创建Image的UI组件,在Image下新建一个B
- 本文实例讲述了Android中系统自带锁WalkLock与KeyguardLock用法。分享给大家供大家参考,具体如下:WalkLock -
- 前言相信做地图社交类APP开发的大家都知道,一般情况下,为了整体的美观和用户体验度,我们需要定制化Marker的样式。本文中实现的方式都是基
- 即刻点赞展示点赞的数字增加和减少并不是整个替换,而是差异化替换。再加上动画效果就看的很舒服。自己如何实现这种数字切换呢?下面用一张图来展示我
- 接下来想做一个图廊,所以并没有必要用立方体,只需做一些“墙壁”就行了。而在一个平面上建起另一个矩形的
- 前言我们在日常的开发中有时候会遇到需要用到相机的需求,而相机也是很常用的东西,例如扫二维码啊拍照上传啊等等。这里我不讲像qq那样自定义很强的
- 本文实例为大家分享了Android滑动组件悬浮固定在顶部效果的具体代码,供大家参考,具体内容如下要想实现的效果是如下:场景:有些时候是内容中
- 特性(Attribute)是将额外数据关联到一个属性(以及其他构造)的一种方式,而枚举则是在编程中最常用的一种构造,枚举本质上其实是一些常量
- WPF实现窗体中的悬浮按钮,按钮可拖动,吸附停靠在窗体边缘。控件XAML代码:<Button x:Class="SunCre
- 很多APP都有侧滑菜单的功能,部分APP左右都是侧滑菜单~SlidingMenu 这个开源项目可以很好帮助我们实现侧滑功能,如果对Slidi