系列目录
【Spring Cloud Alibaba】(一)微服务介绍 及 Nacos注册中心实战
【Spring Cloud Alibaba】(二)微服务调用组件Feign原理+实战
本文目录
前言
书接上文,我们掌握了Feign的基本使用、核心原理,以及Spring Cloud Alibaba如何快速整合Feign,真的太简单了!你是不是觉得这样就够了?但在实际项目使用OpenFeign时,我们常常会遇到各种需求,需要用到它提供的扩展,例如日志分析、自定义统一拦截器、客户端组件配置、GZIP压缩等等,这也正是我接下来在本文中分享的内容:首先我会从原生Feign扩展点配置
入手,然后进行OpenFeign扩展点配置
实战,最后对OpenFeign是如何实现的进行了源码解读
,内容很详细,Let’s go!
一、Feign扩展点配置
在上文,我们主要讲解了架构图的上部和下部,本文主要针对架构图
的 中间扩展部分
!
Feign本身提供了很多扩展点,例如:
- 日志级别logLevel
- 契约contract
- 客户端client
- 超时设置options
- 编码器encoder
- 解码器decoder
- 拦截器requestInterceptor
这些扩展点,我们在使用原生Feign时,可以通过Feign.Builder
指定,最后再通过target
生成动态代理类,完成Bean注册。
举个例子:
@Bean
public UserService userService() {
return Feign.builder()
.logLevel(Logger.Level.BASIC)
.contract(new Contract.Default())
.client(new Client.Default(null, null))
.encoder(new Encoder.Default())
.decoder(new Decoder.Default())
.target(UserService.class, "http://demo-b");
}
二、OpenFeign扩展点配置
通过上文的OpenFeign实战,我们很容易搭建出Spring Cloud Alibaba微服务框架,并实现服务之间通过OpenFeign调用。如果还未看过上文的同学,建议先看上文:【Spring Cloud Alibaba】(二)微服务调用组件Feign原理+实战
我这里准备了3个Spring Cloud Alibaba微服务:demo-a、demo-b、demo-c,之所以准备3个服务是为了验证配置是全局有效还是局有效!
在OpenFeign中扩展配置项,可以通过配置文件
和Java Bean
两种方式,接下来我们就配置试试看!
1. 通过配置文件配置
application.properties,格式:
feign.client.config.{服务名}.{配置名} = {配置值}
我们配置一些你可能用的上的扩展项,比如:日志级别配置
、契约配置
、超时配置
、编解码配置
、拦截器配置
,如下:
# 日志级别配置
feign.client.config.default.loggerLevel = BASIC
# 契约配置
feign.client.config.default.contract = feign.Contract.Default
# 连接超时配置
feign.client.config.default.connectTimeout = 5000
# 读取超时配置
feign.client.config.default.readTimeout = 30000
# 编码器配置
feign.client.config.default.encoder = feign.jackson.JacksonEncoder
# 解码器配置
feign.client.config.default.decoder = feign.jackson.JacksonDecoder
# 拦截器配置, 是数组, 需要自定义RequestInterceptor
feign.client.config.default.requestInterceptors[0]=com.tiangang.demo.c.interceptor.MyFeignRequestInterceptor
有效范围说明
全局生效
:配置 {服务名} 为 default ,如上面例子中所示局部生效
:配置 {服务名} 为 具体服务名
例如,下面的配置仅对调用demo-b服务
有效。
feign.client.config.demo-b.loggerLevel = BASIC
验证是否生效
你知道如何快速验证吗?
挨个试?😏😏😏 教你一个简单有效的方法:
我使用demo-c发起调用,可以在启动demo-c 启动服务 时,构建 动态代理前 打断点查看Feign.Builder。
即在FeignClientFactoryBean.loadBalance
方法的调target
之前打断点:
- 配置后的
Feign.Builder
,确认已经按application.properties配置:
- 如果未配置,默认的
Feign.Builder
如下:
对于是全局还是局部有效,我是确认过的,因为不好演示,所以大家有兴趣可以自行验证确认!
2. 通过Java Bean配置
通过Java代码配置的话需要定义一个配置类,例如我命名为:FeignConfig
,里面定义需要配置的@Bean
,与上面配置文件的配置项保持一致
!为了做区分,这里将编解码器改为Gson。
public class FeignConfig {
// 日志级别配置
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
// 契约配置
@Bean
public Contract feignContract() {
return new Contract.Default();
}
// 超时配置
@Bean
public Request.Options options() {
return new Request.Options(5000, 30000);
}
// 编解码器配置Jackson
/*@Bean
public Encoder encoder() {
return new JacksonEncoder();
}
@Bean
public Decoder decoder() {
return new JacksonDecoder();
}*/
// 编解码器配置Gson
@Bean
public Encoder encoder() {
return new GsonEncoder();
}
@Bean
public Decoder decoder() {
return new GsonDecoder();
}
// 拦截器配置
@Bean
public MyFeignRequestInterceptor myFeignRequestInterceptor() {
return new MyFeignRequestInterceptor();
}
}
有效范围说明
全局生效(扫描到的所有服务)
,两种方式:- 1.在FeignConfig上加
@Configuration
注解(需要保证能扫描到) - 2.在启动类的
@EnableFeignClients
注解中配置defaultConfiguration
- 1.在FeignConfig上加
@EnableFeignClients(defaultConfiguration = FeignConfig.class)
局部生效(指定服务)
:在接口API的@FeignClient
注解中配置
@FeignClient(value = "demo-b", configuration = FeignConfig.class)
验证是否生效
这里直接到FeignClientFactoryBean.loadBalance
方法的target
生成动态代理之前打断点查看:
- Java Bean配置后的
Feign.Builder
对于是全局还是局部有效,我是确认过的,因为不好演示,所以大家有兴趣可以自行验证确认!
补充说明1. 日志级别
Feign提供了4种日志级别
:
日志级别 | 简单说明 |
---|---|
NONE | 默认值,不记录日志 |
BASIC | 记录请求方法、请求URL、响应状态代码、执行时间 |
HEADERS | 在BASIC级别的基础上,记录请求和响应的header |
FULL | 记录全部日志:请求和响应的header、body和metadata |
注意:
若要正常输出日志,需要配置接口包路径
的日志级别,我这里是com.tiangang.demo.api
,所以 application.properties 配置:
# 格式:logging.level.{feign接口包路径}=debug/info...
logging.level.com.tiangang.demo.api=debug
补充说明2. 契约contract
在OpenFeign下,大部分情况下不需要配置contract,但如果老项目已经定义了大量的feign注解,那么就没必要再改成SpringMvc注解了,直接改contract是个好办法!
OpenFeign的默认contract是SpringMvcContract
,即支持SpringMvc注解。
如果修改为feign.Contract.Default
,测试时别忘了加feign注解,否则会编译报错。
补充说明3. 编解码器
使用Jackson
,需要引入依赖:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
使用Gson
,需要引入依赖:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
</dependency>
Gson
的application.properties配置:
feign.client.config.default.encoder = feign.gson.GsonEncoder
feign.client.config.default.decoder = feign.gson.GsonDecoder
Feign本身还提供了很多编解码器,需要的话可以直接用,如下图:
当然了,你也可以自定义编解码器!
补充说明4. 拦截器
拦截器是 非常有用
的扩展点,是我们实现定制化需求的利器!
当我们需要统一处理Header、处理请求参数、处理响应结果时,就可以通过自定义拦截器处理。
Feign默认提供了Basic 认证拦截器,我们可以直接配置使用:
public class FeignConfig {
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("userName", "password");
}
}
另外,我们也可以自定义 ,只需要实现接口RequestInterceptor
public interface RequestInterceptor {
/**
* Called for every request. Add data using methods on the supplied {@link RequestTemplate}.
*/
void apply(RequestTemplate template);
}
例如,上面的例子我自定义实现的拦截器如下:
public class MyFeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
template.header("ACCESS_KEY", "9ZIpCT02u2ctppiXOzbpwBWMtRKPgxKe");
}
}
例子的拦截器就是统一加了一个ACCESS_KEY的header,当你的调用需要统一加header时,就可以使用拦截器实现。当然,不仅用于加header!下面的GZIP压缩就是通过拦截器实现的!
补充说明5. 配置Client
除了上面提到的通用配置方式外,OpenFeign提供了专门的FeignAutoConfiguration
,里面包含对Client
等的配置,帮助我们快速配置Client。
在OpenFeign中,默认的Client是JDK原生的URLConnection,接下来,我们就实战 快速配置 成 Apache HttpClient 和 OkHttp。
1). 配置Client为Apache HttpClient
- 引入依赖
<!-- Apache HttpClient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!-- Feign集成Apache HttpClient -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
- 配置文件中启用
application.properties:
feign.httpclient.enabled=true
参考源码: FeignAutoConfiguration.HttpClientFeignConfiguration
验证已经生效:
2). 配置Client为OkHttp
- 引入依赖
<!-- okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<!-- Feign集成okhttp -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
- 配置