OpenFeign的使用与介绍

OpenFeign

官网 Spring Cloud OpenFeign

参考尚硅谷 https://www.bilibili.com/video/BV1UJc2ezEFU

声明式REST客户端(RestTemplate为编程式REST客户端)

简介

  • Spring Cloud OpenFeign是一种基于Spring Cloud的声明式REST客户端,简化了与HTTP服务交互的过程。

  • 它将REST客户端的定义转化为Java接口,并且可以通过注解的方式来声明请求。

调用注册中心的服务接口

引入依赖

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

启动Feign客户端

(最好标明所在位置)

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.aciu"})
public class OrderMainApplication {
  public static void main(String[] args) {
    SpringApplication.run(OrderMainApplication.class,args);
  }
}

创建Feign客户端

如果遇到相同name或者url,这样它们就会指向同一个服务器,但每个服务器具有不同的自定义配置。需要设置contextId,避免配置冲突

//name是服务的名称
@FeignClient(name = "service-product",contextId = "productAPI")
public interface ProductFeignClient {

  //1、标注在controller上,是接收这样的请求
  //2、标注在FeignClient上,是发送这样的请求
  @GetMapping("/product/getById")
  Product getProduct(@RequestParam Long id);
}

调用第三方接口

GET请求

@FeignClient(name = "thirdPartyService", url = "https://api.example.com")
public interface ThirdPartyServiceClient {

    /**
     * 带参数的 GET 请求
     * @param param1 参数 1
     * @param param2 参数 2
     * @return 响应结果
     */
    @GetMapping("/endpoint")
    String getWithParams(@RequestParam("param1") String param1, @RequestParam("param2") String param2);

    /**
     * 带 Map 参数的 GET 请求
     * @param params 参数 Map
     * @return 响应结果
     */
    @GetMapping("/endpoint")
    String getWithMapParams(@RequestParam Map<String, String> params);
}

POST请求

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@FeignClient(name = "thirdPartyService", url = "https://api.example.com")
public interface ThirdPartyServiceClient {

    /**
     * 带 JSON 体的 POST 请求
     * @param requestBody 请求体
     * @return 响应结果
     */
    @PostMapping("/endpoint")
    String postWithJsonBody(@RequestBody Object requestBody);
}

带请求头的请求

常规做法是放在拦截器里声明

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;

@FeignClient(name = "thirdPartyService", url = "https://api.example.com")
public interface ThirdPartyServiceClient {

    /**
     * 带请求头的 GET 请求
     * @param authorization 授权头
     * @return 响应结果
     */
    @GetMapping("/endpoint")
    String getWithHeader(@RequestHeader("Authorization") String authorization);
}

Feign的主要配置

Feign日志启用

  • 在配置文件启用日志

    • 指定 Feign 客户端接口的全限定名,若要控制单独而非全局输出,则细化到类com.aciu.feign.xxx

    • logging:
        level:
          com.aciu.feign: DEBUG
      
  • 编写全局配置类

    • @Configuration
      public class FeignConfig {
        @Bean
        Logger.Level feignLoggerLevel() {
          return Logger.Level.FULL;
        }
      }
      

Feign超时控制

在这里插入图片描述

若出现相同服务和url,可以通过contextId来区分上下文

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

// 第一个 Feign 客户端
@FeignClient(name = "myFeignClient", contextId = "client1", url = "http://service1.com")
public interface MyFeignClient1 {

    @GetMapping("/resource")
    String getResource();
}

// 第二个 Feign 客户端
@FeignClient(name = "myFeignClient", contextId = "client2", url = "http://service2.com")
public interface MyFeignClient2 {

    @GetMapping("/resource")
    String getResource();
}
spring:
  cloud:
    openfeign:
      client:
        config:
          # 全局客户端配置
          default:
            connectTimeout: 3000
            readTimeout: 3000
            loggerLevel: basic
          # 为第一个 Feign 客户端配置
          client1:
            connectTimeout: 3000
            readTimeout: 3000
            loggerLevel: basic
          # 为第二个 Feign 客户端配置
          client2:
            connectTimeout: 5000
            readTimeout: 5000
            loggerLevel: full

也可以采用配置类来设置

public class MyFeignClientConfiguration {
    @Bean
    public Request.Options options() {
        return new Request.Options(5000, 10000); // 连接超时5秒,读取超时10秒
    }
}


@FeignClient(name = "service-product",
             contextId = "productFeignApiTest",
             configuration = MyFeignClientConfiguration.class)
public interface ProductFeignTest {
  @GetMapping("/product/all")
  List<Product> getAllProduct();
}

Feign重试机制

使用自带重试器

public class FeignConfig {
    @Bean
    public Retryer feignRetryer() {
        // 重试间隔为 100 毫秒,最大重试间隔为 1 秒,最多重试 5 次
        return new Retryer.Default(100, 1000, 5);
    }
}

@FeignClient(name = "service-product",
             contextId = "productFeignApiTest",
             configuration = {MyFeignClientConfiguration.class,
                              RetryFeignConfig.class})
public interface ProductFeignTest {
  @GetMapping("/product/all")
  List<Product> getAllProduct();
}

Feign拦截器

继承feign.RequestInterceptor创建自定义拦截器

@Slf4j
public class DecryptFeignInterceptor implements RequestInterceptor {

  @Override
  public void apply(RequestTemplate template) {
    log.info("============执行解密拦截器============");
    template.header("X-APP-ID","xxxxxx-xxx-xx-xxx-xxxxxxx");
    template.header("X-APP-KEY","xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=");
  }
}

注册配置文件

public class DecryptFeignConfig {
  @Bean
  DecryptFeignInterceptor decryptFeignInterceptor(){
    return new DecryptFeignInterceptor();
  }
}

注入到对应的Feign客户端

@FeignClient(name = "DecryFeignService",
    url = "http://1.1.1.1:1111",
    configuration = DecryptFeignConfig.class)
public interface DecryptFeignClient {
  @PostMapping("/crypt/cryptoRemake")
  Object decryptPhoneNum(@RequestBody DecryptDTO decryptDTO);
}

Feign的FallBack

服务之间的调用可能会因为网络问题、服务超时或服务不可用等原因导致请求失败。为了提高系统的容错性和稳定性,Spring Cloud 提供了 FallbackFallbackFactory 机制,允许开发者定义降级逻辑来处理这些异常情况。当使用 Sentinel 作为熔断器时,可以结合 Sentinel 的规则配置和 OpenFeign 的特性来实现更加灵活的降级策略。

降级策略

  1. 返回固定值或默认值
  2. 使用缓存数据
  3. 抛出异常等

启用sentinel

feign:
  sentinel:
    enabled: true

Fallback 实现

创建一个类实现 Feign 接口,并提供降级逻辑

@Component
public class ExampleServiceFallback implements ExampleServiceClient {

    @Override
    public String getExample() {
        return "Fallback: Service is unavailable.";
    }
}

声明fallback

@FeignClient(name = "example-service", fallback = ExampleServiceFallback.class)
public interface ExampleServiceClient {

    @GetMapping("/api/example")
    String getExample();
}

FallbackFactory实现

创建一个类实现 FallbackFactory<T> 接口,并根据异常信息动态生成降级逻辑:

@Component
public class ExampleServiceFallbackFactory implements FallbackFactory<ExampleServiceClient> {

    @Override
    public ExampleServiceClient create(Throwable cause) {
        return new ExampleServiceClient() {
            @Override
            public String getExample() {
                // 根据异常信息返回自定义的降级逻辑
                return "FallbackFactory: Service is unavailable due to " + cause.getMessage();
            }
        };
    }
}

声明FallbackFactory

@FeignClient(name = "example-service", fallbackFactory = ExampleServiceFallbackFactory.class)
public interface ExampleServiceClient {

    @GetMapping("/api/example")
    String getExample();
}

常问问题

客户端负载均衡与服务端负载均衡的区别
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值