SpringCloud:Feign远程调用
1、Feign替代RestTemplate
1.1 Feign的介绍
- RestTemplate存在的问题
我们之前使用的RestTemplate
远程调用存在着代码可读性差,编程体验不统一,参数复杂URL
难以维护。如果再工作中遇见了类似百度搜索的URL
将难以维护
当我们面对这么长的URL
的时候,当然是希望能够少些甚至不写,最低的要求就是不要再service
层看到这种东西。所以我们就使用了Feign
。
- Feign的介绍
Feign
是一个声明式的http客户端,官方地址:github.com/OpenFeign/f…
其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。 Feign
我理解是常用于微服务相互调用的。
1.2 SpringCloud使用Feign
1. 添加依赖
```
<!-- Feign客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
```
2. 引导类开启功能
在引导类上添加`@EnableFeignClients`注解
```
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
...
}
```
3. 编写Feign客户端
为同一个提供者的服务创建一个接口,里面就替代了所有需要用RestTemplate
远程调用的url
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User queryOrderByUserId(@PathVariable Long id);
}
这个客户端主要是基于SpringMVC
的注解来声明远程调用的信息,比如:
- 服务名称:
userservice
- 请求方式:
GET
- 请求路径:
/user/{id}
- 请求参数:
Long id
- 返回值类型:
User
这样,Feign
就可以帮助我们发送http
请求,无需自己使用RestTemplate
来发送了。
4. 在对应service层中使用
首先将Feign
客户端自动装配,再调用其中的方法。
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2\. 利用 Feign 发送 http 请求到对应的 微服务中
User user = userClient.queryOrderById(orderId);
// 3\. 封装 User 到 Order 中。
order.setUser(user);
// 4.返回
return order;
}
}
2、自定义配置
2.1 Feign自定义配置
Feign可以支持很多的自定义配置,如下表所示:
类型 | 作用 | 说明 |
---|---|---|
feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可。
2.2 配置文件方式
- 全局配置
feign:
client:
config:
# 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
default:
# 日志级别
loggerLevel: FULL
- 单个服务配置
feign:
client:
config:
# 服务名称
userservice:
# 日志级别
loggerLevel: FULL
而日志的级别分为四种:
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
2.3 Java代码方式
先创建Feign
日志级别配置类
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.HEADERS;
}
...
}
- 全局配置
在引导类开启Feign
并传入日志级别配置类@EnableFeignClients(defaultConfiguration = 日志级别配置类.class)
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
...
}
- 单个服务配置
将配置文件放到对应的Feign
客户端的@FeignClient(value = "服务名称", configuration = 日志级别配置类.class)
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration.class)
public interface UserClient {
...
}
2.4 配置优先级
- 当我们在一个项目在
Feign
对相同的服务有着不同的配置,配置文件方式 >Java
代码方式 - 同一个
Java
方式下有不同的配置,根据先后顺序后面的配置覆盖前面的配置

3、Feign使用优化
Feign
作为一个网关,连接使用TCP/IP
协议发起http
请求,依赖于其它的框架。如果频繁发送请求就会有多次的“三次握手四次挥手”。其底层客户端实现包括:
-
URLConnection
:默认实现,不支持连接池 -
Apache HttpClient
:支持连接池 -
OKHttp
:支持连接池
为了减少频繁请求的情况下资源的消耗,所以在优化方面可以着力于客户端底层使用连接池代替默认的URLConnection
。下面我们就用Apache HttpClient
来演示。
3.1 Apache HttpClient使用
1. 引入依赖
<!--httpClient的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2. 配置
feign:
httpclient:
# 开启 httpClient
enabled: true
# 连接池最大连接数
max-connections: 200
# 单个服务最大占用连接数
max-connections-per-route: 50
4、最佳实践
4.1 统一父接口标准
我们可以发现,Feign
的客户端和提供者的controller
层是非常相似的

所以为了让代码简化,我们可以将Feign
客户端和提供者controller
层提作为接口放在一个微服务中,通过引入微服务将对应的接口导入。
4.2 抽取Feign
独立模块
将FeiginClient
抽取成独立的模块,并且将接口有关的pojo
、默认的Feign
配置都放到这个模块中,提供给所有消费者使用。
1. 创建Feign-api
模块
2. 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3. 将对应的FeignClient
和接口相关的pojo
以及默认的配置都放在项目中
[图片上传失败...(image-c3dcce-1653662031811)]
4. 在使用Feign
的项目引导类上,开启扫描Feign-api
模块对应的位置
- 我们可以将
Feign-api
模块内某个包下的所有FeignClient
都扫描进去。通过@EnableFeignClients(clients = basePackages = "包路径")
完成。 - 我们可以将
Feign-api
模块下指定的FeignClient
字节码扫描。通过@EnableFeignClients(clients = {clients.class, clients.class})
5. 启动服务,就成功了。
作者:何鸭子
链接:https://juejin.cn/post/7101677917725753375
来源:稀土掘金