第04章-Feign声明式HTTP客户端
# 4.1 Feign基本使用
# 4.1.1 Feign整合
Feign是Netflix开源的声明式HTTP客户端
整合三板斧:
加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
1
2
3
4加注解
@SpringBootApplication @EnableFeignClients public class ContentCenterApplication {}
1
2
3写配置(暂时没有)
# 4.1.2 Feign基本使用
编写FeignClient接口
@FeignClient("user-center") // 对应远程服务名称
public interface UserCenterFeignClient {
@GetMapping("/users/{id}") // 对应远程接口endpoint
UserDTO findById(@PathVariable Integer id);
}
2
3
4
5
6
使用自动生成的实现类调用远程服务
@Service
public class ShareService {
// 注入FeignClient
@Autowired
private UserCenterFeignClient userCenterFeignClient;
public ShareDTO findById(Integer id) {
// ...
// 使用FeignClient直接调用
UserDTO userDTO = userCenterFeignClient.findById(userId);
// ....
return shareDTO;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 4.2 Feign组成
接口 | 作用 | 默认值 |
---|---|---|
Feign.Builder | Feign的入口 | Feign.Builder |
Client | Feign底层用什么去请求 | 和Ribbon配合时:LoadBalancerFeignClient 不和Ribbon配合时:feign.Client.Default |
Contract | 契约,注解支持 | SpringMvcContract |
Encoder | 编码器,用于将对象转换成HTTP请求消息体 | SpringEncoder |
Decoder | 解码器,将响应消息体转换成对象 | ResponseEntityDecoder |
Logger | 日志管理器 | SIf4jLogger |
Requestinterceptor | 用于为每个请求添加通用逻辑 | 无 |
# 4.3 Feign配置
# 4.3.1 自定义Feign日志级别
级别 | 打印内容 |
---|---|
NONE(默认值 | 不记录任何日志 |
BASIC | 仅记录请求方法、URL、响应状态代码以及执行时间 |
HEADERS | 记录BASIC级别的基础上,记录请求和响应的header |
FULL | 记录请求和响应的header、body和元数据 |
# 针对指定服务配置
方式一、Java代码配置方式
编写配置类
/**
* Feign的配置类
* 这个类别加@Configuration注解,否则必须挪到@ComponentScan包扫描以外,
* 不然会有父子上下文问题,变成全局配置
*/
public class UserCenterFeignConfig {
@Bean
public Logger.Level level() {
// 让Feign打印所有日志细节
return Logger.Level.FULL;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
FeignClient引入配置类
@FeignClient(name = "user-center", configuration = UserCenterFeignConfig.class) // 对应远程服务名称
public interface UserCenterFeignClient {}
2
配置文件添加日志级别,这个是必须的,无论Java代码方式还是注解方式
logging:
level:
com.lucifer.contentcenter.feignclient.UserCenterFeignClient: debug
2
3
方式二、配置文件方式
# 配置日志级别
logging:
level:
com.lucifer.contentcenter.feignclient.UserCenterFeignClient: debug
# feign配置
feign:
client:
config:
# 想要调用的微服务名称
user-center:
loggerLevel: full
2
3
4
5
6
7
8
9
10
11
12
# 全局配置
方式一、Java代码配置方式
代码方式又分为以下两种:
让父子上下文CemponentScan重叠(强烈不建议使用)启动类上的注解配置属性:@EnableFeignClients(defaultConfiguration=xxx.class)
// 启动类 @SpringBootApplication @EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class) public class ContentCenterApplication {} // 配置类 public class DefaultFeignConfig { @Bean public Logger.Level level() { return Logger.Level.FULL; } }
1
2
3
4
5
6
7
8
9
10
11
12
方式二、配置文件方式
# 配置日志级别
logging:
level:
com.lucifer.contentcenter.feignclient.UserCenterFeignClient: debug
# feign配置
feign:
client:
config:
default:
loggerLevel: full
2
3
4
5
6
7
8
9
10
11
# 4.3.2 Feign支持的配置项
代码方式支持的配置:
配置项 | 作用 |
---|---|
Logger.Level | 指定日志级别 |
Retryer | 指定重试策略 |
ErrorDecoder | 指定错误解码器 |
Request.Options | 超时时间 |
Collection | 拦截器 |
SetterFactory | 用于设置Hystrix的配置属性,Feign整合Hystrix才会用 |
属性方式支持的配置:
feign.client.config:
<feignName>:
connectTimeout: 5000 #连接超时时间
readTimeout: 5000 #读取超时时间
1oggerLeve1: ful1 #日志级别
errorDecoder: com.examp1e.SimpleErrorDecoder #错误解码器
retryer: com.example.simpleRetryer #重试策略
requestInterceptors:
-com.example.FooRequestInterceptor #拦截器
#是否对404错误码解码
#处理逻辑详见feign.SynchronousMethodHandler#executeAndDecode
decode404: false
encoder: com.example.SimpleEncoder #编码器
decoder: com.example.SimpleDecoder #解码器
contract: com.example.SimpleContract #契约
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 4.3.3 Feign配置最佳实践
Ribbon和Feign配置对比:
Feign代码和属性配置方式对比:
配置方式 | 优点 | 缺点 |
---|---|---|
代码配置 | 基于代码,更加灵活 | 如果Feign的配置类加了Configuration注解,需注意父子上下文 线上修改得重新打包、发布 |
属性配置 | 易上手 配置更加直观 线上修改无需重新打包、发布 优先级更高 | 极端场景下没有代码配置方式灵活 |
最佳实践:
- 尽量使用属性配置,属性方式实现不了的情况下再考虑用代码配置
- 在同一个微服务内尽量保持单一性,比如统一使用属性配置,不要两种方式混用,增加定位代码的复杂性
# 4.4 Feign继承
FeignClient注解所在的接口和远程服务的Controller极度相似,可以抽象出一个接口,放在一个独立maven模板,服务提供者和消费者都引入该模块。服务提供者Controller实现该接口,服务消费者的FeignClient接口继承该接口。这样就可以实现代码重用,且修改后不用多处修改。
虽然Feign有该特性,但是Spring官方不推荐这样使用,因为官方认为微服务之间应该相互独立,不应该这样耦合。
但是该方式在业界很流行,使用时权衡利弊即可。
# 4.5 Feign脱离Ribbon使用
模拟使用FeignClient访问百度
@FeignClient(name = "baidu", url = "http://www.baidu.com")
public interface BaiduFeignClient {
@GetMapping("")
String index();
}
2
3
4
5
# 4.6 Feign和RestTemplate对比
角度 | RestTemplate | Feign |
---|---|---|
可读性、可维护性 | 一般 | 极佳 |
开发体验 | 欠佳 | 极佳 |
性能 | 很好 | 中等(RestTemplate的50%左右) |
灵活性 | 极佳 | 中等(内置功能可满足绝大多数需求) |
# 4.7 Feign性能优化
Feign默认使用URLConnection发起请求,不支持连接池,可以配置让Feign底层使用OKHttp或Apache HttpClient,它们是支持连接池的。
以Apache HttpClient为例,配置如下:
加依赖
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>
1
2
3
4写配置
feign: httpclient: # 让feign底层使用apache httpclient,而不是默认的URLConnection enabled: true # feign最大连接数 max-connections: 200 # feign单个路径最大连接数 max-connections-per-route: 50
1
2
3
4
5
6
7
8
还可以通过为Feign配置合适的日志级别优化性能,默认的NONE肯定是最好的。
# 4.8 Feign更多参考
参考:Feign常见问题总结 (opens new window)
包括:
[使用Feign实现Form表单提交](