完美解决SpringCloud-OpenFeign使⽤okhttp替换不⽣效问题事发地
原默认的Feign是使⽤URLConnector进⾏通信的,当换为okhttp时,直接引⼊包及配置以下内容根本不⽣效,还是⾛原⽣的。
feign:
okhttp:
enable: true
事件还原
创建项⽬并引⼊pom相关的依赖如下:
springcloud和springboot<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xs
d">
<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);
}
}
配置⽂件
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 = "localhost:8761",fallback = FallbackService.class)
public interface HelloFeignService {
@RequestMapping(value = "/query/eureka-server",method = RequestMethod.GET)
String helloFeign();
}
案件还原
写好上述的配置与类后,开始DEBUG,下图是Controller的DEBUG⼊⼝:
进⼊代理类查看HTTPCLIENT使⽤的是哪⼀个
到下图时就要注意了,这才是进⼊使⽤client的⼊⼝
结果看下图:
参考
经过查资料,有⽂章提到是⾃动配置类的问题FeignAutoConfiguration,⽂章参考:⽂章提到,由于@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);
⽅法所在位置如下:
t.support.AbstractApplicationContext#finishBeanFactoryInitialization
注意事项
在主类添加的⽅法⽤来创建okhttp时,⽅法名⼀定要写成下图的这样,不然创建不了feignClient这个bean。
不知道是否有其他⽅法。这个估计是与org.springframework.cloud.openfeign.FeignAutoConfiguration.OkHttpFeignConfiguration#feignClient有关,相当于创建的⽅法是⼀个重写的过程。
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。如有错误或未考虑完全的地⽅,望不吝赐教。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。