SpringCloud 使用 OpenFeign
一、为什么使用 OpenFeign
在 Spring Cloud 中,使用 OpenFeign主要是为了简化微服务之间的通信,特别是在服务调用的过程中。OpenFeign 是一个声明式的 Web 服务客户端,它能够通过简单的注解方式,快速构建 RESTful 风格的 HTTP 请求。具体来说,使用 OpenFeign 的原因包括以下几个方面:
- 简化 HTTP 请求的编写
OpenFeign 通过注解来声明服务接口,使得微服务之间的通信变得更加简单和直观。开发者只需要定义接口并通过注解描述 HTTP 请求的方式,无需手动编写底层的 HTTP 客户端代码。这样可以减少大量冗余代码,提升开发效率。
示例代码:
// name 服务名称 path 服务路径 configuration 配置类 (可以设置对应的日志级别,需在 yml 中 指定系统级别低于feign的日志级别)
// 服务 路径名 都需要按照调用 Controller 接口的路径来写
//@FeignClient(name = "stock-service", path = "/stock", configuration = OrderConfig.class)
@FeignClient(name = "stock-service", path = "/stock")
public interface StockFeignService {
上述代码中,@FeignClient 注解会告诉 Spring Cloud 自动为 StockClient 接口生成一个代理类,并处理与 stock-service 服务之间的 HTTP 请求。
-
集成负载均衡
Feign 在 Spring Cloud 中默认与 Ribbon 或 Spring Cloud LoadBalancer 集成,能够自动为服务提供负载均衡支持。无需额外的配置,通过 @FeignClient 注解,Feign 会自动从注册中心(如 Nacos、Eureka 等)获取服务实例列表,并进行负载均衡。 -
集成熔断器(Hystrix)
OpenFeign 可以与 Hystrix 或 Resilience4j 等熔断器库集成,从而提供服务调用的容错处理能力。通过声明式注解,开发者可以为 Feign 客户端方法配置熔断规则,避免服务调用失败导致的级联故障。
@FeignClient(name = "stock-service", fallback = StockFallback.class)
public interface StockClient {
@GetMapping("/stock/test")
String getStockInfo();
}
@Component
public class StockFallback implements StockClient {
@Override
public String getStockInfo() {
return "Stock service is unavailable";
}
}
通过上述配置,当 stock-service 服务不可用时,StockFallback 类会返回备用响应,避免整个系统因某个服务故障而崩溃。
- 自动处理序列化与反序列化
Feign 支持自动处理请求和响应的序列化与反序列化。默认情况下,Feign 使用 Jackson 或 Gson 序列化和反序列化请求和响应体。开发者无需手动处理 HTTP 请求的 JSON 序列化工作。
@FeignClient(name = "stock-service")
public interface StockClient {
@PostMapping("/stock/update")
void updateStock(@RequestBody Stock stock);
}
这里 Stock 类会自动通过 Feign 转换成 JSON 格式的请求体发送出去。
- 支持 Spring AOP(面向切面编程)
Feign 可以与 Spring AOP 结合,支持在服务调用前后进行额外的处理。比如,可以利用 Spring AOP 来记录请求日志、添加请求头、进行安全认证等。
通过 @FeignClient,你可以很容易地与其他 Spring 组件集成,加入日志、监控、身份认证等功能。
-
提高代码可维护性
使用 Feign 可以减少服务间调用的样板代码,使得代码更加清晰和简洁。在大型微服务系统中,管理多个 HTTP 客户端非常麻烦,而 Feign 可以统一管理所有服务的 HTTP 请求,减少代码重复和维护成本。 -
与 Spring Cloud 其他组件无缝集成
Feign 是 Spring Cloud 生态中的一部分,它能够与 Eureka、Config、Hystrix、Ribbon 等组件无缝集成。借助 Spring Cloud 的其他功能,Feign 可以自动配置、自动发现服务,并处理服务间的请求路由、负载均衡、容错等问题。 -
支持异步调用
Feign 还支持异步调用(在使用 @Async 或 @EnableAsync 注解时),通过结合 Spring 的异步机制,能够提高请求的并发能力和系统的响应性。
使用 OpenFeign 的好处主要体现在以下几个方面:
- 简化微服务间的 HTTP 调用,减少重复代码;
- 集成负载均衡 和 容错处理,提高系统可靠性;
- 自动处理序列化 和 反序列化,减少手动配置的工作量;
- 与 Spring Cloud 生态无缝集成,支持与其他 Spring Cloud 组件共同工作;
- 提供 异步调用 和 AOP 支持,增强灵活性。
在 Spring Cloud 微服务架构中,OpenFeign 是一种非常高效、简洁的服务间通信方式,特别适合用于 RESTful 风格的 API 调用。
二、如何使用OpenFeign
1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、添加接口
// name 服务名称 path 服务路径 configuration 配置类 (可以设置对应的日志级别,需在 yml 中 指定系统级别低于feign的日志级别)
// 服务 路径名 都需要按照调用 Controller 接口的路径来写
//@FeignClient(name = "stock-service", path = "/stock", configuration = OrderConfig.class)
@FeignClient(name = "stock-service", path = "/stock")
public interface StockFeignService {
@GetMapping("/test")
String testStock();
}
其中:我 stock-service 服务下的 服务实现是这样的:
进行对比,可以发现,接口的实现,和我们Controller 层非常相似
我们使用注解实现只需确认:
- xxxxx-service 要使用的服务
- 服务的path 路径和对应的请求
- 参数及请求方式,保持完整一致即可
3、查看调用日志配置
(1)通过注解配置实现
// 使用注解配置:接口添加注解
@FeignClient(name = "stock-service", path = "/stock", configuration = OrderConfig.class)
// 配置文件中
// 此处配置为全局日志:所有的 feign 都会用到,单独设置可在 feign 接口,或 yml 配置文件设置
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
(2)通过yml文件配置
spring:
application:
name: order
cloud:
# feign 的局部日志级别
openfeign:
client:
config:
stock-service:
loggerLevel: basic
# SpringBoot 的默认日志级别为 info ,feign的 debug 日志级别就不会输入,所以指定对应的文件夹 日志
logging:
level:
com.zjl.order.feign: debug
配置的等级有如下四种:
4、超时时间配置
(1)、通过配置项全局配置;
// 超时时间配置
@Bean
public Request.Options options() {
return new Request.Options(600, TimeUnit.SECONDS,600,TimeUnit.SECONDS,true);
}
(2)通过yml文件配置
spring:
application:
name: order
cloud:
# feign 的局部日志级别
openfeign:
client:
config:
default: # 默认配置,若服务无特殊指定,则使用默认配置
loggerLevel: basic
connect-timeout: 1000
read-timeout: 1000
stock-service: # 服务有特殊指定,则使用指定参数
connect-timeout: 5000
read-timeout: 5000
5、自定义拦截器设置(request/response)
通过实现接口:RequestInterceptor 实现自定义请求拦截器
通过实现其:public void apply(RequestTemplate template) {} 方法,实现自定义逻辑
通过实现接口:ResponseInterceptor 实现自定义结果拦截器
通过实现其:public Object aroundDecode(InvocationContext invocationContext) {} 方法,实现自定义逻辑 该拦截器系统配置中,单个服务只允许一个,响应流只允许读取一次,如果多次读取,可能需要重新设置相应流
@Slf4j
//@Component
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
template.header("feign-request", "feign-request");
log.info("FeignRequestInterceptor:【{}】", template.path());
}
}
@Slf4j
//@Component
public class FeignResponseInterceptor implements ResponseInterceptor {
@Override
public Object aroundDecode(InvocationContext invocationContext) {
log.info("FeignResponseInterceptor:【{}】", invocationContext.response());
return invocationContext.proceed();
}
}
// 在配置类中进行配置
// feign 的全局拦截器 (在发送请求前,进行拦截)
@Bean
public RequestInterceptor requestInterceptor()
{
return new FeignRequestInterceptor();
}
// feign 的全局拦截器 (在收到返回结果后,进行拦截)
@Bean
public ResponseInterceptor responseInterceptor()
{
return new FeignResponseInterceptor();
}
全局实现方式存在两种
- 使用配置类注解 如:@Component
- 使用@Bean在配置类中设置
针对注册服务实现拦截器
spring:
cloud:
openfeign:
client:
config:
default: # 默认配置,若服务无特殊指定,则使用默认配置
loggerLevel: basic
connect-timeout: 10000
read-timeout: 10000
stock-service: # 服务有特殊指定,则使用指定参数
connect-timeout: 5000
read-timeout: 5000
request-interceptors:
- com.zjl.order.interceptor.FeignRequestInterceptor
#request-interceptors[0]: com.zjl.order.interceptor.FeignRequestInterceptor
response-interceptor: com.zjl.order.interceptor.FeignResponseInterceptor
其中:
equest-interceptors
:是一个列表(注意:列表有两种配置形式)response-interceptor
:是单个类(响应流只允许消费一次)