5

Spring Cloud 远程调用 OpenFeign 这些知识点,能颠覆你的认知!

 11 months ago
source link: https://www.51cto.com/article/769702.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Spring Cloud 远程调用 OpenFeign 这些知识点,能颠覆你的认知!

作者:Springboot实战案例锦集 2023-10-13 08:52:19
实现的原理也比较简单就是:向容器中注册了一个OptionsFactoryBean类型的bean且该Bean的作用域范围是refresh。当我们调用/refresh endpoint后就会刷新该Bean的配置信息。

环境:SpringBoot2.7.12 + Spring Cloud2021.0.7

Spring Cloud Openfeign是一种声明式、模板化的HTTP客户端,主要用于在Spring Cloud微服务架构中进行服务调用。

相比于传统的RestTemplate,Openfeign更加简洁,开发者只需通过编写一个接口并添加注解进行配置,即可实现对服务提供方接口的绑定,而无需手动构造请求和解析返回数据。

Openfeign的应用,让Spring Cloud微服务调用变得更加便捷。在服务消费者中,只需通过接口方法即可进行远程服务调用,就像调用本地方法一样简单。此外,Feign还集成了LoadBalancer,利用LoadBalancer维护服务提供方列表,实现轮询调用服务提供者。

使用Spring Cloud Openfeign,开发者可以更加专注于业务逻辑而不是底层的HTTP请求,提高了开发效率和代码可读性。同时,Openfeign还支持自定义配置和扩展,可以满足不同场景下的需求。总之,Spring Cloud Openfeign是Spring Cloud微服务架构中不可或缺的一部分,可以帮助开发者更加高效地进行服务调用。

2. 准备环境

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

开启openfeign功能

@SpringBootApplication
@EnableFeignClients
public class SpringCloudComprehensiveApplication {
}

feign客户端

@FeignClient(
    url = "http://localhost:8088/demos", 
    name = "demoService"
)
public interface DemoFeign {


  @GetMapping("/info/{id}")
  public Object info(@PathVariable("id") Integer id) ;
  
}

以上DemoFeign就能被正确的使用了。接下来看看下面的那些知识点你是知道的

3. 知识盲区

盲区1:超时时间

默认情况下feign调用超时时间如下:

/**
 * 默认超时时间
 * <ul>
 * <li>Connect Timeout: 10 seconds</li>
 * <li>Read Timeout: 60 seconds</li>
 * <li>Follow all 3xx redirects</li>
 * </ul>
 */
public Options() {
  this(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
}
public class FeignClientFactoryBean {
  // 读超时时间
  private int readTimeoutMillis = new Request.Options().readTimeoutMillis();
  // 连接超时时间
  private int connectTimeoutMillis = new Request.Options().connectTimeoutMillis();
}

编程方式自定义:你只需要提供Request.Options类型的Bean即可。

#全局定义
feign.client.config.default.connect-timeout=3000
feign.client.config.default.read-timeout=3000
#具体服务定义
feign.client.config.demoService.connect-timeout=2000
feign.client.config.demoService.read-timeout=2000

盲区2:重试

feign的重试相信很多人都没有玩过对吧?

如果feign没有启用断路器功能(feign.circuitbreaker.enabled, 默认值为false),那么会开启retryer(重试)功能;默认情况openfeign提供了如下配置:

@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
  return Feign.builder().retryer(retryer);
}
// 默认还是个不支持重试的,所以我们需要自定义重试Bean
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
  return Retryer.NEVER_RETRY;
}

自定义重试bean

@Bean
public Retryer feignRetryer() {
  Retryer.Default retryer = new Retryer.Default(100, SECONDS.toMillis(1), 2);
  return retryer ;
}

这样如果当前环境没有cricuitbreaker,那么这里的重试就能生效了。

盲区3:服务降级

通常定义了feign客户端后,我们都会定义相应的降级服务,fallback或fallbackFactory,如果这两个都配置了那谁才会生效呢?源码如下:

class FeignCircuitBreakerTargeter implements Targeter {
  public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
      Target.HardCodedTarget<T> target) {
    // ...
    FeignCircuitBreaker.Builder builder = (FeignCircuitBreaker.Builder) feign;
    String name = !StringUtils.hasText(factory.getContextId()) ? factory.getName() : factory.getContextId();
    // 先判断了fallback属性,如果不是void,那么直接返回了
    Class<?> fallback = factory.getFallback();
    if (fallback != void.class) {
      return targetWithFallback(name, context, target, builder, fallback);
    }
    Class<?> fallbackFactory = factory.getFallbackFactory();
    if (fallbackFactory != void.class) {
      return targetWithFallbackFactory(name, context, target, builder, fallbackFactory);
    }
    return builder(name, builder).target(target);
  }
}

盲区4:primary属性

在@FeignClient注解中有个primary属性,你知道这个属性有什么用吗?

默认每一个feign客户端都被注册为bean,并且每个bean都相当于使用了@Primary注解修饰一样,任何地方注入都是有限注入的该bean。它的用处还得从fallback属性说起。如果定义了feign客户端后对应的fallback是需要实现当前这个feign接口的,且还的注册为bean对象。那么如果把这里的primary设置为false后,容器中此时可是存在两个DemoFeign类型的bean的,这时候容器启动就会报错了。所以这里默认就吧feign客户端的primary设置为true就是解决这个问题的。示例如下:

@FeignClient(
    url = "http://localhost:8088/demos", 
    name = "demoService", 
    fallback = DemoFeignFallback.class
    primary = true // 默认即为true
)
public interface DemoFeign {}


@Component
public class DemoFeignFallback implements DemoFeign {
}

盲区5:动态刷新超时时间

盲区1中已经提到了超时时间问题,那都是写静态配置,那能不能动态配置呢?可以,完全可以,你只需下面这样操作即可

#开启刷新配置
feign.client.refresh-enabled=true

实现的原理也比较简单就是:向容器中注册了一个OptionsFactoryBean类型的bean且该Bean的作用域范围是refresh。当我们调用/refresh endpoint后就会刷新该Bean的配置信息。

先就列出上面5个知识点吧,看看你知道几个?

完毕!!!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK