SpringCloud 使用 OpenFeign

一、为什么使用 OpenFeign

在 Spring Cloud 中,使用 OpenFeign主要是为了简化微服务之间的通信,特别是在服务调用的过程中。OpenFeign 是一个声明式的 Web 服务客户端,它能够通过简单的注解方式,快速构建 RESTful 风格的 HTTP 请求。具体来说,使用 OpenFeign 的原因包括以下几个方面:

  1. 简化 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 请求。

  1. 集成负载均衡
    Feign 在 Spring Cloud 中默认与 Ribbon 或 Spring Cloud LoadBalancer 集成,能够自动为服务提供负载均衡支持。无需额外的配置,通过 @FeignClient 注解,Feign 会自动从注册中心(如 Nacos、Eureka 等)获取服务实例列表,并进行负载均衡。

  2. 集成熔断器(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 类会返回备用响应,避免整个系统因某个服务故障而崩溃。

  1. 自动处理序列化与反序列化
    Feign 支持自动处理请求和响应的序列化与反序列化。默认情况下,Feign 使用 Jackson 或 Gson 序列化和反序列化请求和响应体。开发者无需手动处理 HTTP 请求的 JSON 序列化工作。
@FeignClient(name = "stock-service")
public interface StockClient {
    @PostMapping("/stock/update")
    void updateStock(@RequestBody Stock stock);
}

这里 Stock 类会自动通过 Feign 转换成 JSON 格式的请求体发送出去。

  1. 支持 Spring AOP(面向切面编程)
    Feign 可以与 Spring AOP 结合,支持在服务调用前后进行额外的处理。比如,可以利用 Spring AOP 来记录请求日志、添加请求头、进行安全认证等。

通过 @FeignClient,你可以很容易地与其他 Spring 组件集成,加入日志、监控、身份认证等功能。

  1. 提高代码可维护性
    使用 Feign 可以减少服务间调用的样板代码,使得代码更加清晰和简洁。在大型微服务系统中,管理多个 HTTP 客户端非常麻烦,而 Feign 可以统一管理所有服务的 HTTP 请求,减少代码重复和维护成本。

  2. 与 Spring Cloud 其他组件无缝集成
    Feign 是 Spring Cloud 生态中的一部分,它能够与 Eureka、Config、Hystrix、Ribbon 等组件无缝集成。借助 Spring Cloud 的其他功能,Feign 可以自动配置、自动发现服务,并处理服务间的请求路由、负载均衡、容错等问题。

  3. 支持异步调用
    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 服务下的 服务实现是这样的:
image

进行对比,可以发现,接口的实现,和我们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

配置的等级有如下四种:
image
image

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:是单个类(响应流只允许消费一次)
posted @ 2024-12-17 23:44  代码红了一大片  阅读(20)  评论(0编辑  收藏  举报