完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题
事发地
原默认的Feign是使用URLConnector进行通信的,当换为okhttp时,直接引入包及配置以下内容根本不生效,还是走原生的。
feign: okhttp: enable:true
事件还原
创建项目并引入pom相关的依赖如下:
1.8 org.springframework.cloud spring-cloud-dependencies Finchley.RELEASE pom import `` org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test
启动类
@SpringBootApplication @EnableFeignClients publicclassCh21OpenFeignApplication{ publicstaticvoidmain(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 publicclassHelloFeignController{ @Autowired privateHelloFeignServicehelloFeignService; @RequestMapping(value="/helloFeign",method=RequestMethod.GET) publicObjecthelloFeign(){ returnhelloFeignService.helloFeign(); } }`
service
@FeignClient(name="feign-client",url="http://localhost:8761",fallback=FallbackService.class) publicinterfaceHelloFeignService{ @RequestMapping(value="/query/eureka-server",method=RequestMethod.GET) StringhelloFeign(); }
案件还原
写好上述的配置与类后,开始DEBUG,下图是Controller的DEBUG入口:
进入代理类查看HTTPCLIENT使用的是哪一个
到下图时就要注意了,这才是进入使用client的入口
结果看下图:
参考
经过查找资料,有文章提到是自动配置类的问题FeignAutoConfiguration,文章参考:www.nhooo.com/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) publicClientfeignClient(){ returnnewOkHttpClient(this.okHttpClient); }
当我在主类添加以下代码时,得到的bean如下:
注意:feignClient这个bean是一个loadBalancerFeignClient
@Bean publicokhttp3.OkHttpClientokHttpClient(){ returnnewokhttp3.OkHttpClient.Builder() .readTimeout(60,TimeUnit.SECONDS) .connectTimeout(60,TimeUnit.SECONDS) .writeTimeout(120,TimeUnit.SECONDS) .connectionPool(newConnectionPool()) //.addInterceptor(); .build(); }
当我在主类再追加以下代码时,得到的bean如下:
注意:feignClient这个bean,是我们要找的okhttp了
@Bean @ConditionalOnMissingBean({Client.class}) publicClientfeignClient(okhttp3.OkHttpClientclient){ returnnewfeign.okhttp.OkHttpClient(client); }
真正的真相
这个要再多看下创建流程,从代码上分析,这时在有newfeign.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有关,相当于创建的方法是一个重写的过程。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。