共计 4988 个字符,预计需要花费 13 分钟才能阅读完成。
起源: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 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!