SpringCloud-OpenFeign使用用okhttp替换不生效问题

事发地

原默认的Feign是使用URLConnector进行通信的,当换为okhttp时,直接引入包及配置以下内容根本不生效,还是走原生的。

feign:
  okhttp:
    enable: true

事件还原

创建项目并引入pom相关的依赖如下:


<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.8java.version>
    properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>Finchley.RELEASEversion>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    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入口:
SpringCloud-OpenFeign使用用okhttp替换不生效问题_第1张图片
进入代理类查看HTTPCLIENT使用的是哪一个
SpringCloud-OpenFeign使用用okhttp替换不生效问题_第2张图片
到下图时就要注意了,这才是进入使用client的入口
SpringCloud-OpenFeign使用用okhttp替换不生效问题_第3张图片
SpringCloud-OpenFeign使用用okhttp替换不生效问题_第4张图片
结果看下图:
SpringCloud-OpenFeign使用用okhttp替换不生效问题_第5张图片

参考

经过查找资料,有文章提到是自动配置类的问题FeignAutoConfiguration,文章参考:https://www.cnblogs.com/mufeng3421/p/11442412.html
文章提到,由于@ConditionalOnMissingBean({okhttp3.OkHttpClient.class})导致了无法注入OkHttpClient
SpringCloud-OpenFeign使用用okhttp替换不生效问题_第6张图片

个人猜测

在只添加依赖包时,还没有自行创建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);
		}

SpringCloud-OpenFeign使用用okhttp替换不生效问题_第7张图片

当我在主类添加以下代码时,得到的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();
   }

SpringCloud-OpenFeign使用用okhttp替换不生效问题_第8张图片

当我在主类再追加以下代码时,得到的bean如下:
注意:feignClient 这个bean,是我们要找的okhttp了

    @Bean
    @ConditionalOnMissingBean({Client.class})
    public Client feignClient(okhttp3.OkHttpClient client) {
        return new feign.okhttp.OkHttpClient(client);
    }

SpringCloud-OpenFeign使用用okhttp替换不生效问题_第9张图片

真正的真相

这个要再多看下创建流程,从代码上分析,这时在有new feign.okhttp.OkHttpClient(client); 这一段代码,重新把okhttp注入后,才使得feignClient 名称对应的bean为okhttp。不防从以下代码进行分析:

LoadBalancerFeignClient 的来源

如下图,LoadBalancerFeignClient是继承了Client,进入实现类feign.Client.Default,这个类全程都只有使用HttpURLConnection,所以无论怎样都只能获取到的是默认的JDK里的http的client
SpringCloud-OpenFeign使用用okhttp替换不生效问题_第10张图片
所以这个类创建后要想使用okhttp,那么就只能重新创建把旧的bean冲掉,还好,在主类添加的@Bean创建的类正是在完成bean后再执行这里主类增加的@Bean创建的对象,所以最后加载过程中又会执行bean生命周期的finishBeanFactoryInitialization(beanFactory);
方法所在位置如下:
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization

注意事项

在主类添加的方法用来创建okhttp时,方法名一定要写成下图的这样,不然创建不了feignClient这个bean。不知道是否有其他方法。这个估计是与org.springframework.cloud.openfeign.FeignAutoConfiguration.OkHttpFeignConfiguration#feignClient有关,相当于创建的方法是一个重写的过程。
SpringCloud-OpenFeign使用用okhttp替换不生效问题_第11张图片

借阅说明

感谢下面的文章作者 - 沐风之境,大家可以查看一下他的文章说明,在实现上是使用一个配置类的方式实现 的。
https://www.cnblogs.com/mufeng3421/p/11442412.html

你可能感兴趣的:(springcloud,java,spring)