首页 > 其他分享 >真实案例:Feign 切换 okhttp 无法生效,被老大骂的有点慌!

真实案例:Feign 切换 okhttp 无法生效,被老大骂的有点慌!

时间:2023-06-14 10:48:38浏览次数:64  
标签:Feign 老大 配置 feign class okhttp OkHttpClient public

来源:https://www.cnblogs.com/mufeng3421/p/11442412.html

提示:如果只看如何解决问题,请看文章的末尾如何解决这个问题

1. 场景描述

最近项目中使用了feign当做http请求工具来使用、相对于httpclient、resttemplate来说,fegin用起来方便很多。然后项目有httptrace的需求,需要输出请求日志。

所以就开启了feign自己的日志,发现它自带的日志是debug级别才能打印。而且是逐行打印的,看日志非常的不方便。所以需要输出json格式的日志最好。

2.解决步骤

2.1 引入feign依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${自行选择适合项目的版本}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

这里使用了spring-cloud-openfeing来避免自己手工实现feign的注入,用法上和feign一样

推荐一个开源免费的 Spring Boot 实战项目:

https://github.com/javastacks/spring-boot-best-practice

2.2 配置feign

在入口类上添加 @EnableFeignClients 注解

@SpringBootApplication
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

使用feing自己的Contract,方便使用feign自己的注解来声明http接口。这里使用了一个配置类

@Configuration
public class FeignConfig {
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }
}

2.3 声明接口

只需要声明一个带有@FeignClient注解的接口,就声明好了一个Feign的http请求接口

@FeignClient(name = "accessPlatform", url = "${url.access-platform}")
public interface AccessPlatformFeignClient {
    @RequestLine("GET /access-platform/resource")
    List<AccessResource> queryResourceList(@QueryMap Map<String, Object> query);
}

3.切换Feign的客户端为OkHttp

由于feign自带的http客户端实现是HttpURLConnection,没有连接池功能,可配置能力也比较差,因此我们使用okhttp作为底层的http客户端的具体实现。

3.1 引入okhttp的依赖

 <dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>${feign-okhttp.version}</version>
</dependency>

3.2 修改之前的FeignConfig配置类

问题就出在这里、不过先不急,我们继续

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignConfig {
    // 注入feignContract
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

    // 注入自定义的okHttpClient
    @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())
            .build();
    }
}

开启okhttp作为feign的客户端

# application.yml
feign:
    okhttp:
        enabled: true

一切完美、网上的许多博客也都是这么写的。然后它们告诉你已经配置完了?呵呵,你们到底自己试过没有??

3.3 试着请求一下

当然这里出问题了,发出的请求并非来自okhttp,还是默认的JDK的HttpURLConnection,问题出在哪里呢?接着看

4.找出问题所在

我怀疑是feing在注入配置的时候,根本就没有运行关于okhttp的配置

4.1 查看服务启动时feign配置过程

1.将服务根日志级别调整为debug级别

logging:
    level:
    	root: debug

2.启动服务、查看控制台输出

控制台输出

看到没,okhttp的配置不符合配置运行条件。

3.查询 FeignAutoConfiguration 这个配置类的细节

@Configuration
@ConditionalOnClass({Feign.class})
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {
		// .....其他的配置
  	@Configuration
    @ConditionalOnClass({OkHttpClient.class})
    @ConditionalOnMissingClass({"com.netflix.loadbalancer.ILoadBalancer"})
    @ConditionalOnMissingBean({okhttp3.OkHttpClient.class})
    @ConditionalOnProperty({"feign.okhttp.enabled"})
    protected static class OkHttpFeignConfiguration {
       // ...okhttp的配置
    }

  	// .....其他的配置
}

就是这个自动配置类搞的鬼、当我看到 @ConditionalOnMissingBean({okhttp3.OkHttpClient.class}) 这个注解时,我就明白了。
翻成白话就是,只有当容器中没有OkHttpClient的实例时。他才会运行。如果在 FeignAutoConfiguration之前注入了我们自己定义的OkHttpClient实例,那不好意思,我不干了?无不注入。

5.解决问题

既然自动配置不干,那我们自己动手干。拷贝 FeignAutoConfiguration 配置类中的配置过程,粘贴在FeignConfig配置类中手动注入feign的client。Ok!完美解决。

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureAfter(FeignAutoConfiguration.class)
public class FeignConfig {
//    private okhttp3.OkHttpClient okHttpClient;

    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

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

    @Bean
    @ConditionalOnMissingBean({ConnectionPool.class})
    public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties, OkHttpClientConnectionPoolFactory connectionPoolFactory) {
        Integer maxTotalConnections = httpClientProperties.getMaxConnections();
        Long timeToLive = httpClientProperties.getTimeToLive();
        TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
        return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
    }

    @Bean
    public OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
        Boolean followRedirects = httpClientProperties.isFollowRedirects();
        Integer connectTimeout = httpClientProperties.getConnectionTimeout();
        Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
        return httpClientFactory.createBuilder(disableSslValidation)
                .connectTimeout((long)connectTimeout, TimeUnit.MILLISECONDS)
                .followRedirects(followRedirects)
                .connectionPool(connectionPool)
                .addInterceptor(new OkHttpLogInterceptor()) // 自定义请求日志拦截器
                .build();
    }
}

6.小结

如果你没有耐心看完所有的过程的话。就记住一句话:用自己手动注入Feign的Client实现,来代替 Feign的自动配置所做的过程就好了。具体的配置请看第5点。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

标签:Feign,老大,配置,feign,class,okhttp,OkHttpClient,public
From: https://www.cnblogs.com/javastack/p/17479522.html

相关文章

  • com.netflix.hystrix.exception.HystrixRuntimeException: xxxFeign#xxxx timed-out a
    问题描述在使用Feign进行远程调用时遇到的bug。原因是因为超时了。需要对超时时间进行设置一下即可。在Nacos进行设置原先的contentTimeout和readTimeout都是2000,修改成20000后bug便解决了。......
  • springboot - feign.FeignException$BadRequest: [400] during [GET] to [http:
    ERROR失败原因:、feign.FeignException$BadRequest:[400]during[GET]to[http://方法?携带的请求头条件。。。。。[ManualStockControllerFeign#deleteManualStockTaskByIds(List)]:<!doctypehtml><htmllang="en"><head><title>HTTPStatus400–Bad......
  • 微服务之间的调用方式RestTemplate和FeignClient
    SpringCloud服务间的调用有两种方式:RestTemplate和FeignClient。不管是什么方式,他都是通过REST接口调用服务的http接口,参数和结果默认都是通过jackson序列化和反序列化。因为SpringMVC的RestController定义的接口,返回的数据都是通过Jackson序列化成JSON数据。一、RestTemplate使用......
  • spring cloud 之 openfeign 记录(通过feign上传)
    今日搭建好nacos nacos踩坑记录迫不及待的进入了下一步,服务间的远程调用,就踩了一个小小的坑 我做的是一个阿里oss上传的服务!阿里oss服务个人可以有三个月试用,对新手非常的友好首先是一个openfeign编写上的问题@RequestMapping(value="/common/oss/download",meth......
  • Feign使用实践
    Feign是一个声明式的HTTP客户端,用于简化微服务架构中的服务调用。它基于注解和接口定义,可以与服务发现组件(例如Eureka)和负载均衡组件(例如Ribbon)集成,提供了更简洁、可读性更高的代码来实现服务间的通信。下面是使用Java代码实现Feign入门示例的详细步骤:添加依赖项:在您的Java......
  • 从删库到跑路,老大爷学Java的心酸历程
    大家好,我是程序员青戈,一个被Bug耽误了才艺的程序员......
  • 4.OpenFeign
    5.OpenFeignOpenFeign主要基于接口和注解实现了远程调用5.1.简介官网:https://docs.spring.io/spring-cloud-openfeign/docs/2.2.4.RELEASE/reference/html/#spring-cloud-feignFeign是声明性(注解)Web服务客户端。它使编写Web服务客户端更加容易。要使用Feign,先创建一个接......
  • OpenFeign
    OpenFeign简介Feign是一个声明式的WebService客户端,是一种声明式、模板化的HTTP客户端。OpenFeign是SpringCloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产......
  • java.lang.NoClassDefFoundError: okhttp3/Callback(已解决)
    今天在向MinIO上传文件时出现:java.lang.NoClassDefFoundError:okhttp3/Callback 但是的确已经导过包了,如图: 经过测试,应该时版本问题所致,这里修改版本以后成功解决。  ......
  • Android tcp、okhttp请求&&python tcp&&a bytes-like object is required, not ‘str
    更多内容欢迎来到我的新博客blog.devilwst.top更多内容欢迎来到我的新博客blog.devilwst.top首先声明一下,本文部分代码来自于博客AndroidpublicstaticvoidGetByHttpURL(finalStringurl){newThread(newRunnable(){@Overridepublicvo......