完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题

事发地

原默认的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有关,相当于创建的方法是一个重写的过程。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 基于Feign使用okhttp的填坑之旅

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

  • 使用okhttp替换Feign默认Client的操作

    一 关键pom <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Cloud OpenFeign的Starter的依赖 --> <dependency> &l

  • SpringCloud Open feign 使用okhttp 优化详解

    我就废话不多说了,大家还是直接看代码吧~ <!--web 模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <!--排除tomcat依赖 --> <exclusion> <artifactId&

  • SpringCloud OpenFeign Post请求400错误解决方案

    在微服务开发中SpringCloud全家桶集成了OpenFeign用于服务调用,SpringCloud的OpenFeign使用SpringMVCContract来解析OpenFeign的接口定义. 但是SpringMVCContract的Post接口解析实现有个巨坑,就是如果使用的是@RequestParam传参的Post请求,参数是直接挂在URL上的. 问题发现与分析 最近线上服务器突然经常性出现CPU高负载的预警,经过排查发现日志出来了大量的OpenFeign跨服务调用出现400的错误(HT

  • 完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题

    事发地 原默认的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" xml

  • SpringCloud OpenFeign 服务调用传递 token的场景分析

    目录 业务场景 RequestInterceptor 多线程环境下传递 header(一) 分析 inheritableRequestAttributesHolder 原理 分析 inheritableRequestAttributesHolder 失效原因 多线程环境下传递 header(二) 控制主线程在子线程结束后再结束 重新保存 request 的 header 结语 业务场景 通常微服务对于用户认证信息解析有两种方案 在 gateway 就解析用户的 token 然后路由的时候把 us

  • 完美解决js传递参数中加号和&号自动改变的方法

    在action中用get方法获得参数,如果参数里有"+",要做处理,否则到后台会变成空格. 解决方案: 1 .改用post方法: 2 .在 js 里用 url = encodeURI(encodeURI(XXX)) ,后台再解码一次: 3 .传递参数的时候直接替换转义,或者直接写转义后的代码 data =  "a + b": data = data.replace(/\+/g, "+"); data = data.replace(/\&/

  • ECSHOP完美解决Deprecated: preg_replace()报错的问题

    随着PHP5.5 的普及,ECSHOP系统又爆出了新的错误.PHP发展到PHP5.5版本以后,有了很多细微的变化.而ECSHOP官方更新又太慢,发现这些问题后也不及时升级,导致用户安装使用过程中错误百出.说了半天,这个新错误到底是什么呢,它的完整错误提示信息是这样的: Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in....... 注意:不是所有人的ECS

  • 完美解决Android Studio集成crashlytics后无法编译的问题

    问题描述: 在用fabric集成后编译出现如下错误, Error:Cause: hostname in certificate didn't match: <maven.fabric.io> != <*.motili.com> OR <*.motili.com> OR <motili.com> build.gradle部分脚本(fabric插件自动生成的): buildscript { repositories { maven { url 'https://

  • CodeIgniter 完美解决URL含有中文字符串

    codeIgniter默认的配置下是不允许URL中包含非ASCII字符的,如果URL中含非ASCII字符,那么CI会毫不客气的抛出错误.本文章向码农介绍CodeIgniter 如何解决URL含有中文字符串. 你 可能会说,那我把这个URL使用函数urlencode一下呢?不行.因为Web Server会在接收到一个被urlencode的URL后自动将其decode,然后在PHP里得到的这些字符串转换成他原来所代表的含义,并使用 Web Server自己的URL编码字符集(IIS6 中文版是GBK

  • 完美解决PJ的Cookies保存时限问题!可选择记录登陆时长!

    http://mr-w.cn/一直被这个问题所困扰!!现在终于完美解决啦!!献给那些需要前台记住登录信息的朋友!(此方法经过我的使用验证不存在星铃丹管理员所说的后台会持续登陆的安全隐患...后台还是和原版一样的,效果只针对前台!!)感谢Wady和IFairy...请大家不要只看不回,只回不来我的博客坐坐...回帖是美德!做人要厚道!! 下面是修改方法... 1.首先修改common/checkUser.asp(主要是这个!!)将以下原码 [Copy to clipboard]CODE:'进行MD

  • 完美解决mac环境使用sed修改文件出错的问题

    sed是linux命令,用于处理文件内容(修改,替换等),mac中都可以使用,但发现相同的替换命令在linux可以正常执行,在mac则执行失败. 出错原因 用shell写了个更新Config/Config.php版本的脚本,代码如下: #!/bin/bash file='Config/Config.php' old_version='1.1.0' new_version='1.1.1' #替换配置文件版本 sed -i "s/$old_version/$new_version/g" &

  • Linux服务器tomact 8.0启动慢的完美解决方法

    环境信息: CentOS release 6.8 tomcat-8.0 JDK1.8 一.启动tomcat #sh /root/tomcat-8.0/bin/startup.sh #tailf /root/tomcat-8.0/logs/catalina.out 26-Aug-2017 12:58:31.661 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selec

  • 完美解决IIS服务器无法加载应用程序 '/LM/W3SVC/1/ROOT'-没有注册类别的问题

    现象:        浏览ASP页面提示   500内部错误 事件查看器中:        [1]:                服务器无法加载应用程序 '/LM/W3SVC/1/ROOT'.错误是 '没有注册类别'.                 有关此消息的详细信息,请访问 Microsoft 联机支持站点: http://www.microsoft.com/contentredirect.asp. 有关更多信息,请参阅在 http://go.microsoft.com/fwlink/e

随机推荐