起源: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@EnableFeignClientspublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
应用feing本人的Contract,方便使用feign本人的注解来申明http接口。这里应用了一个配置类
@Configurationpublic 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.ymlfeign: 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开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!