本文介绍: SpringCloud OpenFeign功能配置详解(一文吃透OpenFeign),会对部分OpenFeign源码解析,也会对OpenFeign中的坑做说明

目录

一、简介

OpenFeign客户端一个web声明http远程调用工具直接可以根据服务名称注册中心拿到指定服务IP集合,提供了接口和注解方式进行调用,内嵌集成了Ribbon本地负载均衡器

二、feign和OpenFeign的区别

1、底层都是内置了Ribbon,去调用注册中心服务
2、Feign是Netflix公司写的,是SpringCloud组件中的一个轻量级RESTful的HTTP服务客户端,是SpringCloud中的第一代负载均衡客户端
3、OpenFeign是SpringCloud自己研发的,在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。是SpringCloud中的第二代负载均衡客户端
4、Feign本身不支持Spring MVC的注解使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心服务
5、OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理方式产生实现类,实现类中做负载均衡并调用其他服务

三、SpringCloud集成OpenFeign

版本说明
Spring Cloud Version:Hoxton.SR12
Spring Boot Version:2.3.12.RELEASE
不同版本源码可能会有差异

1、引入starter

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

2、在启动或者配置类上加@EnableFeignClients注解

@SpringBootApplication
@EnableFeignClients
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3、声明Feign接口

@FeignClient(value = "kerwin-user",contextId = "userInfoClient")
public interface UserInfoClient {
    /** 获取用户信息 */
    @GetMapping("/user-info/info/{id}")
    String getInfo(@PathVariable("id") Long id);
}

4、@FeignClient 属性介绍

@FeignClient用于标记一个接口为Feign客户端,@FeignClient中的属性可以使用 ${feign.name} 这种方式取值

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface FeignClient {

	// namevalue属性用于标注客户端名称,也可以用${propertyKey}获取配置属性
	@AliasFor("name")
	String value() default "";

	// 该类的Bean名称 PS: 这个配置很重要后续会详细介绍
	String contextId() default "";

	// namevalue属性用于标注客户名称,也可以用${propertyKey}获取配置属性
	@AliasFor("value")
	String name() default "";

	// 弃用 被qualifiers()替代。
	@Deprecated
	String qualifier() default "";

	// 模拟客户端的@Qualifiers值。如果qualifier()和qualifiers()都存在我们使用后者,除非qualifier()返回数组为空或只包含空值空白值,在这种情况下,我们将首先退回到qualifier(),如果也不存在,则使用default = contextId + "FeignClient"。
	String[] qualifiers() default {};

	// 绝对URL或可解析主机名 PS: 使用这个配置后只能定型发送没有负载均衡能力
	String url() default "";

	// 是否应该解码404而不是抛出FeignExceptions
	boolean decode404() default false;

	// 用于模拟客户端的自定义配置类。可以包含组成客户部分覆盖@Bean定义,默认配置都在FeignClientsConfiguration类中,可以指定FeignClientsConfiguration类中所有的配置
	Class<?>[] configuration() default {};

	// 指定失败回调
	Class<?> fallback() default void.class;

	// 为指定的假客户接口定义一个fallback工厂fallback工厂必须生成fallback类的实例,这些实例实现了由FeignClient注释的接口。
	Class<?> fallbackFactory() default void.class;

	// 所有方法映射使用的路径前缀
	String path() default "";

	// 是否虚拟代理标记为主bean。默认为true
	boolean primary() default true;
}

5、@EnableFeignClients 属性介绍

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {

	// 扫描@FeignClient包地址
	String[] value() default {};

	// 用户扫描Feign客户端的包,也就是@FeignClient标注的类,与value同义,并且互斥
	String[] basePackages() default {};

	// basePackages()的类型安全替代方案用于指定要扫描注释的组件的包。每个指定类别的包将被扫描考虑每个包中创建一个特殊的无操作标记类或接口,除了被该属性引用之外没有其他用途
	Class<?>[] basePackageClasses() default {};

	// 为所有客户定制@Configuration,默认配置都在FeignClientsConfiguration中,可以自己定制
	Class<?>[] defaultConfiguration() default {};

	// 可以指定@FeignClient标注的类,如果不为空,就会禁用路径扫描
	Class<?>[] clients() default {};

}

四、默认配置

1、替换默认配置前置说明这里以Feign请求日志为例

2、使用配置文件替换默认配置(推荐使用优先级最高)

2.1、全局请求日志配置
feign:
  client:
    config:
      # 默认配置 如果不单独配置每个服务会走默认配置
      default:
        loggerLevel: FULL # 日志级别 NONE:不打印  BASIC:打印简单信息 HEADERS:打印头信息 FULL:打印全部信息 (默认 NONE
2.2、独立请求日志配置(独立配置优先
feign:
  client:
    config:
      # 配置单独FeignClient
      # @FeignClient(value = "kerwin-user",contextId = "userInfoClient")
      # 如果FeignClient注解设置contextId这里就使用userInfoClient如果没有设置contextId就直接使用服务名称kerwin-user
      userInfoClient:
        loggerLevel: FULL # 日志级别 NONE:默认不打印  BASIC:打印简单信息 HEADERS:打印头信息 FULL:打印全部信息(默认 NONE
2.3、源码分析为什么使用配置文件配置优先级最高

通过配置文件配置其实最后加载的,会将其它地方配置的信息全部顶掉有兴趣可以看看源码 FeignClientFactoryBean.configureFeign 这个方法会比其它配置加载执行,会在这里实现替换替换顺序Spring容器中的配置Bean -> 配置文件中的默认配置 -> 配置文件中的独立配置
在这里插入图片描述

3、在@EnableFeignClients中使用缺省(默认)配置类替换默认配置(如果不做特殊处理这个配置类优先级很高会比独立配置还高)

3.1、配置实现
public class FeignCommonSpecification {
    @Bean
    @ConditionalOnMissingBean //这里如果不加@ConditionalOnMissingBean那么独立配置是无法生效的,原理在后面补充
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
  • 在@EnableFeignClients中添加defaultConfiguration
@EnableFeignClients(defaultConfiguration = FeignCommonSpecification.class)
3.2、源码分析为什么使用缺省配置类优先级会那么高

分析这个问题首先要知道Spring的 allowBeanDefinitionOverriding 参数什么,这里简单解释一下,这个参数是控制注册 BeanDefinition 是否可以覆盖加载的,也就是说当这个参数true时Bean的名称相同是可以覆盖的,在Spring的 DefaultListableBeanFactory 我们可以看到这个参数默认为true,也就是说谁后加载那么在 BeanDefinitionMap 中就注册的就是谁,在 NamedContextFactory 的 createContext 方法中我们可以看到是先注册的独立配置然后注册缺省配置,到这里就很明显了缺省配置把独立配置顶替了,在缺省配置的方法中加上 @ConditionalOnMissingBean 可以解决这个问题,还有一点要提一下在SpringBoot中会将 allowBeanDefinitionOverriding 设置为false,但是每个 FeignClient 都会通过创建 NamedContextFactorycreateContext 方法创建一个自己 AnnotationConfigApplicationContext 容器,这个子容器 allowBeanDefinitionOverriding 默认还是true
在这里插入图片描述

4、使用独立配置替换默认配置

  • 先写一个类提供一个日志方法feignLoggerLevel设置一个日志等级,并且使用@Bean标记
    PS:需要特别注意这个类上不能加@Configuration这类注解,如果被Spring扫描到了那么全局都会使用这一个配置
public class UserInfoClientSpecification  {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
@FeignClient(value = "kerwin-user",contextId = "userInfoClient",configuration = UserInfoClientSpecification.class)

五、解决allowbean-definition-overriding问题

启动项目出现这个错误信息

Description:
The bean ‘kerwinuser.FeignClientSpecification’ could not be registered. A bean with that name has already been defined and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

1、错误原因

这个错误是因为出现了重名的Bean名称,在FeignClientsRegistrar注册Feign 配置信息到Spring 中时会组装一个Bean名称,如果在**@FeignClient** 中没有设置contextId 那么会使用value 作为组装名称前缀比如我们多个**@FeignClient** 设置的value 服务称为user 并且没有设置contextId ,那么在注册Bean 信息的时候BeanName 就会重复Spring 原生支持覆盖的,也就是说如果BeanName 相同那么后注册的就会将先注册的替换,但是在SpringBoot 中会将这个覆盖配置关闭,如果出现一样的BeanName 那么就会抛出上面那个异常信息,解决方法常用有两种开启第一种SpringBoot 覆盖配置、第二种在**@FeignClient** 中设置contextId推荐使用第二种,第一种方法别用很坑,网上很多人都是使用第一种方法解决我们公司也是使用的第一种😀。

2、解决方法一(别用)

开启Spring覆盖加载配置,Spring默认是开启的,SpringBoot默认关闭了有兴趣可以看看SpringApplication中的allowBeanDefinitionOverriding属性

spring:
  main:
    allow-bean-definition-overriding: true

3、解决方法二(推荐

给每个@FeignClient都设置自己唯一contextId

@FeignClient(value = "kerwin-user",contextId = "userInfoClient")
public interface UserInfoClient {
}

六、解决GET请求无法传递对象参数问题(使用@SpringQueryMap)

Spring Cloud OpenFeign提供了一个等价的@SpringQueryMap注释用于将POJO或Map参数注释查询参数Map,在参数前加上@SpringQueryMap即可

@FeignClient(value = "demo",contextId = "demoClient")
public interface DemoClient {
    @GetMapping(path = "/demo1")
    String demo1(@SpringQueryMap DemoDTO dto);
}

七、OpenFeign超时配置

OpenFeign超时有多种配置方式,这里介绍几种个人觉得最实用的

1、使用配置文件配置(推荐)

使用配置文件配置是最推荐的,也是在项目中使用最多的。

feign:
  client:
    config:
      # 默认配置 如果不单独配置每个服务会走默认配置
      default:
        connectTimeout: 2000 # 连接超时时间 默认值10000毫秒
        readTimeout: 5000 # 读取超时时间 默认值60000毫秒
      # 配置单独FeignClient
      # @FeignClient(value = "kerwin-user",contextId = "userInfoClient")
      # 如果FeignClient注解设置了contextId这里就使用contextId=userInfoClient如果没有设置contextId就直接使用服务名称kerwin-user
      userInfoClient:
        connectTimeout: 2000 # 连接超时时间 默认值10000毫秒
        readTimeout: 5000 # 读取超时时间 默认值60000毫秒

2、使用@FeignClient配置超时时间

使用@FeignClient注解的configuration属性来指定配置类。

首先,创建一个配置类,继承feign.Request.Options类

public class UserInfoClientSpecification extends Request.Options {
    public UserInfoClientSpecification() {
    	// 设置连接超时时间为2秒,设置读取超时时间为5秒
        super(2, TimeUnit.SECONDS, 5, TimeUnit.SECONDS, true);
    }
}

然后,在使用@FeignClient注解进行声明时,使用configuration属性指定该配置类。

@FeignClient(value = "kerwin-user",contextId = "userInfoClient",configuration = UserInfoClientSpecification.class)
public interface UserInfoClient{
}

3、为单独接口设置超时时间(这种方式优先级比使用配置文件更高)

feign接口里加入Request.Options这个参数就可以单独为接口单独设置超时时间了

@GetMapping("/user-info/info/{id}")
String getInfo(Request.Options options,@PathVariable("id") Long id);

调用的时候new 一下Options对象

String resp = userInfoClient.getInfo(
        new Request.Options(2, TimeUnit.SECONDS, 5, TimeUnit.SECONDS, true),
        666L);

4、通过Ribbon配置文件设置超时时间(不主动设置Feign的超时时间才有效,不推荐使用)

ribbon:
  ConnectTimeout: 2000  #默认 1000毫秒
  ReadTimeout: 5000  #默认 1000毫秒

通过Ribbon配置文件设置超时时间只有在不做任何Feign的超时时间才有效,在LoadBalancerFeignClient.getClientConfig()方法中有一个判断,当Feign的 Request.Options = 默认的Request.Options时会使用Ribbon的超时配置。
在这里插入图片描述

八、OpenFeign重试配置

1、OpenFeign默认重试机制核心

当不做任何配置时OpenFeign默认是会在 FeignLoadBalancer.getRequestSpecificRetryHandler() 方法中获取请求重试处理器,这里可以看到第一个判断就是获取Ribbon中是否开启 OkToRetryOnAllOperations 配置,如果Ribbon配置中开启了那么连接超时和和其它异常导致出问题都会进行重试重试次数也会使用Ribbon中配置的重试次数参数。
在这里插入图片描述

如果Ribbon没有开启 OkToRetryOnAllOperations 配置就会进行下面的判断,当请求不为 GET 请求时只会对连接超时异常进行重试,对其它异常不会重试,因为增删改请求做重试的话可能会导致同一个数据插入两次,对查询请求做重试不会影响正常业务

我这里调试使用的是 GET 请求,会进最下面一个方法,所有异常都会重试,这里重点看一下 **RequestSpecificRetryHandler ** 这个类,这个类是Ribbon处理重试机制核心类,调试进入这个类的构造方法可以看到封装了重试所需要的一些参数,这些参数都是拿的Ribbon默认的参数在后面会具体说如何配置。
在这里插入图片描述

还有一点需要注意如果配置OpenFeign的其它配置,比如在配置文件中配置了Feign的default配置那么这里读取到的IClientConfig中的配置信息就不会是Ribbon的而是OpenFeign自己的配置,那么这个就没有Ribbon这两个重试次数的配置,结合上面几点其实建议使用Ribbon的重试配置。
在这里插入图片描述

总结:也就是说OpenFeign不做任何配置,默认会对不同服务实例切换重试一次,如果不是GET请求那么只会对连接超时进行重试,如请求超时则不会重试,如果对Feign做了哪怕一个配置比如在配置文件中配置了Feign的default请求超时配置那么就无法使用Ribbon的两个重试次数的配置参数默认就是不会进行重试。

2、通过Ribbon配置重试(配置了Feign的配置或者springretry则Ribbon重试配置会失效

一定需要注意一点,如果对Feign做了哪怕一个配置比如在配置文件中配置了Feign的default请求超时配置那么就无法使用Ribbon的两个重试次数的配置参数,默认就是不会进行重试

ribbon:
  MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用  默认0
  MaxAutoRetriesNextServer: 1 #服务实例切换重试次数 默认1
  OkToRetryOnAllOperations: true #是否开启重试机制 默认关闭

FeignLoadBalancer.getRequestSpecificRetryHandler() 方法的入参IClientConfig中可以看到properties中的两个重试次数配置还有是否开启重试机制开关
在这里插入图片描述

3、通过Feign的Retryer接口配置重试(如果在配置文件设置了Feign的Retryer那么Ribbon和springretry的重试机制都会失效

定义一个类继承Retryer.Default

/**
 * 重试策略  默认 重试间隔100毫秒  最大间隔时间1秒  重试5次
 */
@Slf4j
public  class CommonFeignRetry extends Retryer.Default {
    public CommonFeignRetry() {
        // 重试间隔是每次失败之后会等待100毫秒再次发起重试请求的间隔时间
        // 最大间隔时间是每次重试的间隔时间累加起来不能超过这个最大间隔时间,如果超过了就不会在重试,哪怕还没有达到配置的重试次数
        // 重试次数会受最大间隔时间和重试间隔时间影响,如果累计间隔时间超过这个最大间隔时间就不会在重试
        // 重试间隔100毫秒  最大间隔时间1秒  重试5次
        this(100, SECONDS.toMillis(1), 5);
    }

    public CommonFeignRetry(long period, long maxPeriod, int maxAttempts) {
        super(period, maxPeriod, maxAttempts);
    }
    @Override
    public void continueOrPropagate(RetryableException e) {
        log.warn("【FeignRetryAble】Message【{}】", e.getMessage());
        super.continueOrPropagate(e);
    }

    @Override
    public Retryer clone() {
        return new CommonFeignRetry();
    }
}

通过配置文件加载重试配置类
可以做全局默认配置,也可以单独给某个FeignClient配置

feign:
  client:
    config:
      # 默认配置 如果不单独配置每个服务会走默认配置
      default:
        retryer: com.kerwin.config.CommonFeignRetry
      # 配置单独FeignClient
      # @FeignClient(value = "kerwin-user",contextId = "userInfoClient")
      # 如果FeignClient注解设置了contextId这里就使用contextId=userInfoClient如果没有设置contextId就直接使用服务名称kerwin-user
      userInfoClient:
        retryer: com.kerwin.config.CommonFeignRetry

默认的Retryer是在FeignClientsConfiguration 配置类的feignRetryer() 方法中加载的,如果出现异常会直接抛出这个异常不会进行重试处理,在SynchronousMethodHandlerinvoke() 方法中可以看到调用的是那个Retryer,有兴趣可以看看源码
在这里插入图片描述

PS:除了可以通过配置文件配置,当然也可以通过配置类配置,方法和日志配置差不多。

4、通过springretry为每个请求设置重试(如果Feign配置自己的Retryer那么springretry不会生效,但是会比Ribbon优先级高)

首先要引入springretry包,可以不用版本会使用SpringBoot夫包指定的版本

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

如果我们需要为特定的请求设置不同的重试策略,则可以在对应的方法上加上 @Retryable 注解,并指定对应的 Retryer 类型如下所示

@FeignClient(value = "kerwin-user",contextId = "userInfoClient")
public interface UserInfoClient{
    @GetMapping("/user-info/get-user-name/{id}")
    @Retryable(maxAttempts = 2)
    String getUserName(@PathVariable("id") Long id);
}

使用上述方式,我们可以为每个请求设置不同的重试策略,从而更加灵活地处理重试问题。

PS:
注意一个问题,如果项目引入springretry包就算不配置重试GET请求也会默认服务实例切换重试1数使用的是Ribbon的配置,
spring-retry包这里使用的是RetryableFeignLoadBalancer来进行的请求调用和重试处理,在RetryableFeignLoadBalancer.execute()方法中可以看到会去封装一个RetryTemplate,这个RetryTemplate中会设置一个RetryPolicy,如果没有单独配置重试就会使用Ribbon的RibbonLoadBalancedRetryPolicy,在RibbonLoadBalancedRetryPolicy中的变量RibbonLoadBalancerContext里就能看见是如果使用Ribbon配置来进行的重试次数判断

九、OpenFeign请求日志级别配置

  • Feign远程调用时提供了日志打印功能,输出的日志级别为debug,先要把项目的输出日志设置为debug

    // 设置指定日志输出级别为debug,我这里将我自己com.kerwin包所有日志输出级别设置成了debug,根据自己需要来即可
    logging:
      level:
        com:
          kerwin: debug
    
  • 为了更加精细化控制日志输出,Feign还提供了日志内容输出的几个级别。
    NONE:默认的,不显示任何日志。
    BASIC:仅记录请求方法和URL以及响应状态代码和执行时间。
    HEADERS:除了BASIC中定义的信息之外,还有请求和响应头的信息。
    FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据

1、通过配置文件配置(推荐)

feign:
  client:
    config:
      # 默认配置 如果不单独配置每个服务会走默认配置
      default:
        loggerLevel: FULL # 日志级别 NONE:不打印  BASIC:打印简单信息 HEADERS:打印头信息 FULL:打印全部信息 (默认 NONE)
      # 配置单独FeignClient 
      # @FeignClient(value = "kerwin-user",contextId = "userInfoClient")
      # 如果FeignClient注解设置了contextId这里就使用userInfoClient如果没有设置contextId就直接使用服务名称kerwin-user
      userInfoClient:
        loggerLevel: FULL # 日志级别 NONE:默认不打印  BASIC:打印简单信息 HEADERS:打印头信息 FULL:打印全部信息(默认 NONE

2、使用@FeignClient配置

public class UserInfoClientSpecification  {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
@FeignClient(value = "kerwin-user",contextId = "userInfoClient",configuration = UserInfoClientSpecification.class)

十、OpenFeign拦截器

拦截器是OpenFeign可用的一种强大的工具,它可以被用来在请求和响应前后进行一些额外的处理

1、通过OpenFeign请求拦截器设置统一请求头

public class MyHeaderInterceptor implements RequestInterceptor {
    private static String headerName = "token";
    @Override
    public void apply(RequestTemplate requestTemplate) {
        // 在这里添加额外的处理逻辑添加请求头
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
            HttpServletRequest request = attributes.getRequest();
            String value = request.getHeader(headerName);
            requestTemplate.header(headerName, value);
        }
    }
}

在配置文件中添加拦截器配置

feign:
  client:
    config:
      # 默认配置 如果不单独配置每个服务会走默认配置
      default:
        request-interceptors:
          - com.kerwin.config.MyHeaderInterceptor 
      # 配置单独FeignClient 
      # @FeignClient(value = "kerwin-user",contextId = "userInfoClient")
      # 如果FeignClient注解设置了contextId这里就使用userInfoClient如果没有设置contextId就直接使用服务名称kerwin-user
      userInfoClient:
        request-interceptors:
          - com.kerwin.config.MyHeaderInterceptor 

除了在配置文件中配置同时也能在配置类中配置,不过要注意加载优先级问题,推荐使用配置文件。

十一、替换OpenFeign默认HTTP请求框架HttpURLConnection

1、替换成HttpClient

添加POM

<dependency>
	<groupId>io.github.openfeign</groupId>
	<artifactId>feign-httpclient</artifactId>
</dependency>

添加配置

feign:
  httpclient:
    enabled: true # HttpClient开关
    max-connections: 200  # 线程池最大连接数
    max-connections-per-route: 50   # 单个请求路径的最大连接数

2、替换成OkHttp

添加POM

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

添加配置

feign:
  httpclient:
    max-connections: 200 # 线程池最大连接数
  okhttp:
    enabled: true

3、源码断点查看是否生效

调用的是在 FeignLoadBalancer.execute() 方法中,断点可以看到requestclient为OkHttpClient,如果不替换就是HttpURLConnection
在这里插入图片描述

十二、OpenFeign配置hystrix

在配置文件中开启hystrix默认是关闭的

feign:
  # 是否开启hystrix 默认false
  hystrix:
    enabled: true

1、使用@FeignClient中的fallback进行回调(不能控制不同异常的处理逻辑

实现自己对应的FeignClient接口,重写其中的方法,该类一定要能被Spring扫描到,不然无法加载

@Component
public class UserInfoClientFallback implements UserInfoClient {
    @Override
    public String getInfo(Long id) {
        return "服务繁忙";
    }
}

将fallback配置到@FeignClient中

@FeignClient(value = "kerwin-user",contextId = "userInfoClient",fallback = UserInfoClientFallback.class)
public interface UserInfoClient {
    /**
     * 获取用户信息
     */
    @GetMapping("/user-info/info/{id}")
    String getInfo(@PathVariable("id") Long id);
}

当调用对应方法出现异常时则会自动回调UserInfoClientFallback重写的方法。

2、使用@FeignClient中的fallbackFactory进行回调(可以控制对应异常的处理逻辑)

使用@FeignClient中的fallbackFactory需要自己去实现FallbackFactory接口,泛型使用自己对应UserInfoClient,我们实现FallbackFactory接口的create方法可以看到入参是一个Throwable,我们可以对异常类型和异常信息进行对应的处理,该类也一定要能被Spring扫描到,不然无法加载。

PS:要实现的是feign.hystrix.FallbackFactory别实现了org.springframework.cloud.openfeign.FallbackFactor

@Component
public class UserInfoClientFallbackFactory  implements FallbackFactory<UserInfoClient> {
    @Override
    public UserInfoClient create(Throwable cause) {
        UserInfoClient userInfoClient = new UserInfoClient() {
            @Override
            public String getInfo(Long id) {
                cause.printStackTrace();
                return "异常msg=" + cause.getMessage();
            }
        };
        return userInfoClient;
    }
}

将我们实现的FallbackFactory配置到@FeignClient中

@FeignClient(value = "kerwin-user",contextId = "userInfoClient",fallbackFactory = UserInfoClientFallbackFactory.class)
public interface UserInfoClient {
    /**
     * 获取用户信息
     */
    @GetMapping("/user-info/info/{id}")
    String getInfo(@PathVariable("id") Long id);
}

十三、配置Ribbon负载均衡算法

1、单独配置某个服务负载均衡算法(使用全局配置无效

通过配置文件给Ribbon配置负载均衡算法只能单独给某个服务配置,和SpringBoot集成默认的负载均衡算法ZoneAvoidanceRule,使用Ribbon的全局配置是无效的,下面会解释为什么

# 给kerwin-user服务单独配置随机负载均衡算法
kerwin-user:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 随机算法

2、为什么使用配置文件配置Ribbon的全局负载均衡算法会无效

要探究这个问题需要看一下Ribbon和SpringBoot是如何集成的,和OpenFeign其实也类似,Ribbon会给每个服务名称都生成一个自己的Spring上下文管理自己需要的Ribbon的一些组件Bean,比如负载均衡算法组件,Ribbon这里也会提供一个类似FeignClientsConfiguration 缺省配置类RibbonClientConfiguration ,在RibbonClientConfiguration中的ribbonRule() 方法中可以看到如何加载的负载均衡算法组件。

在这里插入图片描述

跟进去propertiesFactory.isSet() 方法一直到PropertiesFactory.getClassName() 方法就能看到是如何获取的我们的配置,这里会组装一个key值去环境变量获取对应的配置值,如果有配置则返回对应的值,如果没有配置则返回空,这个key拼接后为kerwin-user.ribbon.NFLoadBalancerRuleClassName ,正好可以和我们的单独配置对应上,如果是使用全局配置这里是读取不到的。

在这里插入图片描述

原文地址:https://blog.csdn.net/weixin_44606481/article/details/132499972

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_50205.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注