http客户端Feign
目录
1. Feign替代RestTemplate
RestTemplate存在的问题
- 代码可读性差,编程体验不统一
- 参数复杂URL难以维护
restTemplate.getForObject(url, 返回类型);
Feign是一个声明式http客户端,类似Controller调用service。
SpringCloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。
只需要创建一个接口,然后添加注解即可!
调用微服务访问的两种方法
1. 微服务名字【ribbon】
2. 接口和注解【feign】
1. 引入依赖
# 消费者
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. 自动装配
@EnableFeignClients()
publc class XXXAplication(){
......
3. 接口声明
@FeignClient("服务名称")
public interface XXXClient{
@GetMapping("/请求路径") // 请求方式
返回类型 方法名(请求参数);
}
4. FeignClient替代RestTemplate
@Autowired
private XXXClient client;
public YYY xxx(){
......
返回类型 httpResults = client.方法名(请求参数);
......
}
2. 自定义配置
- feign.Logger.Leverl
NONE:没有任何日志(默认)
BASIC:记录请求时间,结束时间,耗时时常
HEADERS:BASIC、请求头、响应体
FULL:BASIC、请求头、请求体、响应体
修改日志级别
- 配置文件
# 1. 全局配置
feign:
client:
config:
default:
loggerLevel: FULL # 日志级别
# 2. 局部配置
feign:
client:
config:
服务名称:
loggerLevel: FULL # 日志级别
- 修改代码
# 创建 FeignClientConfiguration
......
import feign.Logger;
......
public class FeignClientConfiguration{
@Bean
public Logger.Level logLevel(){ # feign.Logger包下的 Logger.Level
return Logger.Level.FULL; // Logger.Level.FULL 枚举类
}
}
# 1. 全局配置 启动类
```java
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
publc class XXXAplication(){
......
# 2. 局部配置 FeignClient接口
@FeignClient("服务名称", configuration = FeignClientConfiguration.class)
public interface XXXClient{
@GetMapping("/请求路径") // 请求方式
返回类型 方法名(请求参数);
}
3. Feign使用优化
Feign底层的客户端实现:
- URLConnection:默认实现,不支持连接池
- Apache HttpClient:支持连接池
- OKHttp:支持连接池
因此优化Feign的性能主要包括
- 使用连接池代替默认的URLConnection
- 日志级别,最好使用basic或none
3.1 引入依赖
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-httpclient -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
3.2 配置文件
根据业务选择 最大连接数
feign:
client:
httpclient:
enabled: true # 开启feign对httpclient的支持
max-connections: 200 # 最大连接数
max-connections-per-route: 50 # 每个路径的最大连接数
4. 最佳实践
4.1 理论
- 继承
消费者 调用 提供者,请求方式、请求地址、请求参数,一致
# 提供者
@RestController
public class AAAController{
......
@GetMapping("/YYY/{id}")
XXX findById(@PathVariable("id" String id));
......
}
# 消费者
@FeignClient("服务名称")
public interface XXXClient{
@GetMapping("/YYY/{id}") // 请求方式
XXX selectById(@PathVariable("id" String id));
}
public interface XXXAPI{
@GetMapping("/YYY/{id}") // 请求方式
XXX findById(@PathVariable("id" String id));
}
# 消费者
@FeignClient("服务名称")
public interface XXXClient extends XXXAPI{
}
# 提供者
@RestController
public class AAAController implements XXXAPI{
......
}
出现的问题:
- 紧耦合
- spring mvc中,方法参数无法继承
- 抽取
随着消费者数量的增加,每个消费者都要编写一个FeignClient,造成重复开发。
将FeignClient抽取为独立模块,并把接口有关的POJO、Feign配置放在该模块中。
出现的问题:
- 引入该消费者不需要的方法
4.2 实现抽取方式
- 创建feign-api的module,引入feign的starter依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 编写Client、实体类、默认配置类
@FeignClient("服务名称")
public interface XXXClient{
@GetMapping("/请求路径") // 请求方式
返回类型 方法名(请求参数);
}
public class XXX{
......
}
public class FeignClientConfiguration{
@Bean
public Logger.Level logLevel(){ # feign.Logger包下的 Logger.Level
return Logger.Level.FULL; // Logger.Level.FULL 枚举类
}
}
- 消费者中引入feign-api
<dependency>
<groupId>feign-api的包名</groupId>
<artifactId>feign-api</artifactId>
</dependency>
- 修改消费者中的相关代码
重新导入 feign-api 中的类
注意:包名不同(feign-api 中的FeignClient与消费者扫描的包不一致时),无法扫描,spring 无法自动注入
// XXXClient 是 feign-api 中的FeignClient
@Autowired
private XXXClient client;
- 指定FeignClient所在的包
# 启动类
@EnableFeignClients(basePackages = "FeignClient所在的包")
- 指定FeignClient字节码
# 启动类
@EnableFeignClients(clients= {XXXClient})
最后
以上是学习 黑马程序员《微服务技术全栈教程》的学习笔记