Spring Cloud OpenFeign实现动态服务名调用的示例代码

 更新时间:2025年06月06日 10:24:38   作者:要阿尔卑斯吗  
在微服务架构中,我们经常需要根据动态传入的服务名来远程调用其他服务,例如,你的业务中可能有多个子服务:service-1、service-2……需要动态决定调用哪个,所以本文给大家介绍了Spring Cloud OpenFeign 实现动态服务名调用指南,需要的朋友可以参考下

场景背景

在微服务架构中,我们经常需要根据动态传入的服务名来远程调用其他服务。例如,你的业务中可能有多个子服务:service-1service-2……需要动态决定调用哪个。

通常我们使用如下方式注入 Feign 客户端:

 @FeignClient(name = "service")
 public interface FeignClient {
     @PostMapping("/api/push")
     void pushMessage(@RequestBody PushMessageRequest request);
 }

但这种写法服务名是静态写死的,不能根据运行时的参数进行动态选择。

错误用法:FeignClientFactory

很多开发者会尝试用 Spring 内部的 FeignClientFactory

 @Resource
 private FeignClientFactory feignClientFactory;
 ​
 FeignClient FeignClient = feignClientFactory.getInstance(serviceName, FeignClient.class);

这种方式只能获取 @FeignClient(name="xxx") 注册的静态实例,而不能真正实现动态服务调用。

  • 适用场景:获取已经 @FeignClient 声明过的 bean。
  • 不适用:动态服务名(如从数据库或配置中传入)+ 动态构建 Feign 实例。

正确方式:自定义动态 Feign 客户端工厂

要想实现真正的动态服务名 + 负载均衡 + 支持配置和拦截器的 Feign 客户端,我们需要手动构造并注入 Feign 客户端

核心思路:

  • 使用 Spring Cloud 提供的 Feign.Builder(必须是 Spring 注入的)
  • 配合 LoadBalancerClient 实现服务发现与负载均衡
  • 手动构建 Feign 接口实例

一、配置 Feign.Builder

 @Configuration
 public class FeignBuilderConfig {
 ​
     @Bean
     @Scope("prototype")
     public Feign.Builder feignBuilder(ObjectFactory<HttpMessageConverters> messageConverters) {
         return Feign.builder()
                 .contract(new SpringMvcContract())
                 .encoder(new SpringEncoder(messageConverters))
                 .decoder(new SpringDecoder(messageConverters))
                 .retryer(new Retryer.Default(100, TimeUnit.SECONDS.toMillis(1), 3))
                 .options(new Request.Options(3000, 5000))
                 .logger(new Logger.ErrorLogger())
                 .logLevel(Logger.Level.BASIC);
     }
 }

二、自定义动态客户端工厂

 @Component
 @Slf4j
 public class DynamicFeignClientFactory {
 ​
     private final Feign.Builder feignBuilder;
     private final LoadBalancerClient loadBalancerClient;
 ​
     public DynamicFeignClientFactory(Feign.Builder feignBuilder,
                                      LoadBalancerClient loadBalancerClient) {
         this.feignBuilder = feignBuilder;
         this.loadBalancerClient = loadBalancerClient;
     }
 ​
     public <T> T getClient(String serviceName, Class<T> clazz) {
         int maxRetry = 3;
         int retryCount = 0;
         Exception lastException = null;
 ​
         while (retryCount < maxRetry) {
             try {
                 ServiceInstance instance = loadBalancerClient.choose(serviceName);
                 if (instance == null) {
                     throw new RuntimeException("未找到可用的服务实例:" + serviceName);
                 }
 ​
                 String url = instance.getUri().toString();
                 log.info("选择的 Feign 客户端目标地址为:{}", url);
                 return feignBuilder.target(clazz, url);
 ​
             } catch (Exception e) {
                 lastException = e;
                 log.warn("第 {} 次尝试获取 Feign 客户端失败,服务名:{},错误信息:{}", retryCount + 1, serviceName, e.getMessage());
                 retryCount++;
                 try {
                     Thread.sleep(500L);
                 } catch (InterruptedException ignored) {}
             }
         }
 ​
         throw new RuntimeException("创建 Feign 客户端失败,服务名:" + serviceName, lastException);
     }
 }

三、使用方式

原始写法(错误):

 @Resource
 private FeignClientFactory feignClientFactory;
 ​
 FeignClient FeignClient = feignClientFactory.getInstance(serviceName, FeignClient.class); 

正确写法:

@Resource
private DynamicFeignClientFactory feignClientFactory;

FeignClient FeignClient = feignClientFactory.getClient(ServerName, FeignClient.class);
FeignClient.pushMessage(new PushMessageRequest(Ids, senderEventMessage));

补充说明

  • Spring 注入的 Feign.Builder 会自动继承全局配置(超时、日志、拦截器等)。
  • 支持服务名动态路由,自动走 Spring Cloud LoadBalancer。
  • 每次调用可绑定到不同的服务实例(支持轮询/自定义负载策略)。
  • 避免直接 new Feign.Builder(),否则会失去 Spring 集成能力。

1. DynamicFeignClientFactory 类

 @Component
 @Slf4j
 public class DynamicFeignClientFactory {
 ​
     private final Feign.Builder feignBuilder;
     private final LoadBalancerClient loadBalancerClient;
 ​
     public DynamicFeignClientFactory(Feign.Builder feignBuilder,
                                      LoadBalancerClient loadBalancerClient) {
         this.feignBuilder = feignBuilder;
         this.loadBalancerClient = loadBalancerClient;
     }
 ​
     public <T> T getClient(String serviceName, Class<T> clazz) {
         ...
     }
 }

功能说明:

这是 动态创建 Feign 客户端 的核心工厂类,解决了 Spring Cloud @FeignClient 无法支持运行时动态服务名的问题。

核心逻辑:

  • 使用 Spring 提供的 LoadBalancerClient 动态选择某个服务的实例(支持 Eureka/Nacos 等注册中心)。
  • 使用 Spring 注入的 Feign.Builder 构建 Feign 客户端实例,绑定目标实例地址
  • 加了简单的重试逻辑(最多3次),提升服务不稳定时的容错性。

为什么不能直接用 FeignClientFactory

  • FeignClientFactory#getInstance 是静态注册的,依赖启动时的 @FeignClient(name="xxx")不能做到动态服务名运行时创建实例
  • 而本类是自己构造目标地址,可通过服务名运行时切换服务。

2. FeignBuilderConfig 类

 @Configuration
 public class FeignBuilderConfig {
 ​
     @Bean
     @Scope("prototype")
     public Feign.Builder feignBuilder(ObjectFactory<HttpMessageConverters> messageConverters) {
         return Feign.builder()
                 .contract(new SpringMvcContract())
                 .encoder(new SpringEncoder(messageConverters))
                 .decoder(new SpringDecoder(messageConverters))
                 .retryer(new Retryer.Default(100, TimeUnit.SECONDS.toMillis(1), 3))
                 .options(new Request.Options(3000, 5000))
                 .logger(new Logger.ErrorLogger())
                 .logLevel(Logger.Level.BASIC);
     }
 }

功能说明:

这是自定义的 Feign 构造器配置,确保动态创建的 Feign 实例拥有 Spring 的 HTTP 编解码器、契约协议、超时、重试等设置

关键配置解读:

配置项作用说明
SpringMvcContract让 Feign 支持 @RequestMapping、@GetMapping 等 Spring MVC 风格注解
SpringEncoder/Decoder使用 Spring Boot 的 HttpMessageConverter 做 JSON 编解码(默认支持 Jackson、Gson 等)
Retryer.Default(...)设置重试机制:初始延迟100ms,最大延迟1s,最多重试3次
Request.Options(...)设置连接超时为3秒,请求响应超时为5秒
Logger.ErrorLogger + BASIC开启日志,仅记录错误请求的基本信息(节省性能)
@Scope("prototype")每次注入都创建一个新的 Feign.Builder(防止多实例干扰)

为什么不能直接用 Feign.builder()

如果你直接用 Feign.builder()

  • 不具备 Spring 编解码器能力;
  • 没有 Spring 的日志、重试、超时等配置支持;
  • 无法识别 @RequestMapping 等注解;
  • 无法使用负载均衡(因为没注入 LoadBalancerClient);

你必须用 Spring 注入的 Feign.Builder,并设置好契约与编解码器,才能让它具备 @FeignClient 的能力。

总结

配置类作用是否必须
DynamicFeignClientFactory实现动态服务名绑定并构建 Feign 客户端
FeignBuilderConfig注入支持 Spring 编解码、契约协议、重试、超时等功能的构造器

这两个配置类结合起来,实现了 “动态服务发现 + 动态客户端构建 + Spring 完整能力支持” ,是 Spring Cloud Feign 动态服务名调用的标准做法之一。

以上就是Spring Cloud OpenFeign实现动态服务名调用的示例代码的详细内容,更多关于Spring Cloud OpenFeign服务名调用的资料请关注脚本之家其它相关文章!

相关文章

  • Java实现对中文字符串的排序功能实例代码

    Java实现对中文字符串的排序功能实例代码

    这篇文章主要介绍了Java实现中文字符串的排序功能实例代码的相关资料,需要的朋友可以参考下
    2016-04-04
  • java实现切图并且判断图片是不是纯色/彩色图片

    java实现切图并且判断图片是不是纯色/彩色图片

    本篇文章主要介绍了java实现切图并且判断图片是否是纯色/彩色图片,具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • springBoot整合jwt实现token令牌认证的示例代码

    springBoot整合jwt实现token令牌认证的示例代码

    实施Token验证的方法挺多的,还有一些标准方法,比如JWT,本文主要介绍了springBoot整合jwt实现token令牌认证的示例代码,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • JFormDesigner(IDEA)下载方法

    JFormDesigner(IDEA)下载方法

    JFormDesigner是一种Java Swing GUI设计工具,可快速创建用户界面,支持多种布局管理器,如GridBagLayout、SpringLayout等,本文给大家介绍JFormDesigner(IDEA)下载方法,感兴趣的朋友跟随小编一起看看吧
    2023-12-12
  • 详解Spring Boot下使用logback 记录多个文件日志

    详解Spring Boot下使用logback 记录多个文件日志

    这篇文章主要介绍了详解Spring Boot下使用logback 记录多个文件日志,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Java漏桶算法的简单代码实例

    Java漏桶算法的简单代码实例

    这篇文章主要介绍了Java漏桶算法的简单代码实例,漏桶算法的意义在于能够平滑请求,不给下游服务造成过大压力,特别适用于突发流量或者定时任务拉取大量数据时,需要处理大量数据或者请求的场景,需要的朋友可以参考下
    2024-01-01
  • SpringBoot中将@Bean方法解析为BeanDefinition详解

    SpringBoot中将@Bean方法解析为BeanDefinition详解

    这篇文章主要介绍了SpringBoot中将@Bean方法解析为BeanDefinition详解,得到的BeanDefinition是ConfigurationClassBeanDefinition类型,会为BeanDefinition设置factoryMethodName,这意味着当实例化这个bean的时候将采用工厂方法,需要的朋友可以参考下
    2023-12-12
  • Java项目防止SQL注入的几种方法总结

    Java项目防止SQL注入的几种方法总结

    SQL注入是比较常见的网络攻击方式之一,在客户端在向服务器发送请求的时候,sql命令通过表单提交或者url字符串拼接传递到后台持久层,最终达到欺骗服务器执行恶意的SQL命令,下面这篇文章主要给大家总结介绍了关于Java项目防止SQL注入的几种方法,需要的朋友可以参考下
    2023-04-04
  • 在spring boot中使用java线程池ExecutorService的讲解

    在spring boot中使用java线程池ExecutorService的讲解

    今天小编就为大家分享一篇关于在spring boot中使用java线程池ExecutorService的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Java算法实现杨辉三角的讲解

    Java算法实现杨辉三角的讲解

    今天小编就为大家分享一篇关于Java算法实现杨辉三角的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01

最新评论