前言:
1. 使用方式分类总览
序号 使用形式 是否基于服务名调用 是否需 @LoadBalanced备注 1 RestTemplate + 自定义负载均衡 ❌ 否(手动拼接URL) ❌ 否 手动选择服务实例 2 RestTemplate + Ribbon(非服务名) ❌ 否(手动拼接URL) ❌ 否 使用 DiscoveryClient+Ribbon手动选节点3 RestTemplate + Spring Cloud LoadBalancer(非服务名) ❌ 否(手动拼接URL) ❌ 否 使用 LoadBalancerClient手动选实例4 RestTemplate + Ribbon(基于服务名) ✅ 是 ✅ 是 自动通过服务名解析 5 RestTemplate + Spring Cloud LoadBalancer(基于服务名) ✅ 是 ✅ 是 推荐替代 Ribbon 6 OpenFeign + Ribbon ✅ 是 ❌ 否 Spring Cloud 2020 以前使用 7 OpenFeign + Spring Cloud LoadBalancer ✅ 是 ❌ 否 Spring Cloud 2020 以后默认方案
2. @LoadBalanced的作用
@LoadBalanced是加在RestTemplate的@Bean上的注解。作用:让这个
RestTemplate支持通过服务名调用,并自动使用 Ribbon 或 Spring Cloud LoadBalancer 做客户端负载均衡。必须加
@LoadBalanced才能支持服务名调用 ,比如restTemplate.getForObject("http://producer/getMember", String.class)。如果没加,
RestTemplate就是普通的,只能用完整 URL(IP+端口)调用,自己拼 URL。
3. 使用Ribbon
java//1.不加也可以,是默认 @Bean public IRule ribbonRule() { return new RandomRule(); //随机策略 return new RoundRule(); // 轮询策略 return new RoundRule(); // 自定义负载均衡策略 } //2. 也可以自定义负载均衡的方式 //@Component 建议采用@Bean方式注入 //原因: //1. 可读性差:别人一看 @Bean 没配置,可能误以为用的默认 RoundRobinRule。 //2. 项目中多个服务时可能出现冲突:比如你给多个服务配置不同的 IRule,使用 @Component 会全局生效,反而不好控制。 public class BoyatopWeightLoadBalance extends AbstractLoadBalancerRule { @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } private AtomicInteger countAtomicInteger = new AtomicInteger(0); @Override public Server choose(Object key) { ILoadBalancer lb = getLoadBalancer(); if (lb == null) { return null; } // 获取该服务接口地址 多个 //获取的同时是该服务没有下线的地址 Server List<Server> upList = lb.getReachableServers(); //目的是单纯server没有实现权重,只有选择nacos的server才可以实现权重 ArrayList<NacosServer> newNacosServers = new ArrayList<>(); upList.forEach((s) -> { NacosServer nacosServer = (NacosServer) s; double weight = nacosServer.getInstance().getWeight(); for (int i = 0; i < weight; i++) { newNacosServers.add(nacosServer); } }); return newNacosServers.get(countAtomicInteger.incrementAndGet() % newNacosServers.size()); } }
4. 使用Spring Cloud LoadBalancer不同于 Ribbon,Spring Cloud LoadBalancer 不支持
IRule,如需更换策略需使用RandomLoadBalancer。若要配置随机策略,需自定义 Spring Cloud LoadBalancer 的配置类。(下面不加也是可以的,为默认的)
java@Configuration public class ProducerLoadBalancerConfig { @Bean public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer( Environment environment, LoadBalancerClientFactory factory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }application.yml:
spring: cloud: loadbalancer: clients: producer: configuration: com.example.ProducerLoadBalancerConfig1. RestTemplate + 自定义负载均衡(手动选择实例 + 手动拼接 URL)
✅ 是否基于服务名:❌ 否
✅ 是否需要
@LoadBalanced:❌ 否✅ 特点:
不依赖 Ribbon 或 LoadBalancer。
手动从注册中心获取实例列表,实现负载均衡逻辑(如随机)。
✅ 示例代码:
java@RestController public class OrderController { @Autowired private DiscoveryClient discoveryClient; @Autowired private RestTemplate restTemplate; @GetMapping("/orderToMember") public String orderToMember() { List<ServiceInstance> instances = discoveryClient.getInstances("producer"); if (instances == null || instances.isEmpty()) return "No instance"; // 随机负载均衡 ServiceInstance instance = instances.get(new Random().nextInt(instances.size())); String url = instance.getUri() + "/getMember"; return restTemplate.getForObject(url, String.class); } @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
2. RestTemplate + Ribbon + 手动拼接 URL(非服务名调用)
✅ 是否基于服务名:❌ 否
✅ 是否需要
@LoadBalanced:❌ 否✅ 特点:
实际并未用到 Ribbon 的服务发现,仅使用 Ribbon 提供的负载策略(如
RandomRule)。使用
LoadBalancerClient.choose()手动选择服务实例。✅ 示例代码:
java@Configuration public class RibbonConfig { //不加也可以,是默认 @Bean public IRule ribbonRule() { return new RandomRule(); //随机策略 return new RoundRule(); // 轮询策略 } @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } @RestController public class OrderController { @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate; @GetMapping("/orderToMember") public String orderToMember() { ServiceInstance instance = loadBalancerClient.choose("producer"); String url = instance.getUri() + "/getMember"; return restTemplate.getForObject(url, String.class); } }
3. RestTemplate + Spring Cloud LoadBalancer + 手动拼接 URL
✅ 是否基于服务名:❌ 否
✅ 是否需要
@LoadBalanced:❌ 否✅ 示例代码:
java@RestController public class OrderController { @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate; @GetMapping("/orderToMember") public String orderToMember() { ServiceInstance instance = loadBalancerClient.choose("producer"); String url = instance.getUri() + "/getMember"; return restTemplate.getForObject(url, String.class); } @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }⚠️ 不同于 Ribbon,Spring Cloud LoadBalancer 不支持
IRule,如需更换策略需使用RandomLoadBalancer。若要配置随机策略,需自定义 Spring Cloud LoadBalancer 的配置类。
java@Configuration public class ProducerLoadBalancerConfig { @Bean public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer( Environment environment, LoadBalancerClientFactory factory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }application.yml:
spring: cloud: loadbalancer: clients: producer: configuration: com.example.ProducerLoadBalancerConfig
4. RestTemplate + Ribbon(基于服务名)
✅ 是否基于服务名:✅ 是
✅ 是否需要
@LoadBalanced:✅ 是✅ 示例代码:
java@Configuration public class RibbonConfig { @Bean public IRule ribbonRule() { return new RandomRule(); } @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } } @RestController public class OrderController { @Autowired private RestTemplate restTemplate; @GetMapping("/orderToMember") public String orderToMember() { return restTemplate.getForObject("http://producer/getMember", String.class); } }
5. RestTemplate + Spring Cloud LoadBalancer(基于服务名)
✅ 是否基于服务名:✅ 是
✅ 是否需要
@LoadBalanced:✅ 是✅ 示例代码:
java@Configuration public class LoadBalancerConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } } @RestController public class OrderController { @Autowired private RestTemplate restTemplate; @GetMapping("/orderToMember") public String orderToMember() { return restTemplate.getForObject("http://producer/getMember", String.class); } }若要配置随机策略,需自定义 Spring Cloud LoadBalancer 的配置类。
java@Configuration public class ProducerLoadBalancerConfig { @Bean public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer( Environment environment, LoadBalancerClientFactory factory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }application.yml:
spring: cloud: loadbalancer: clients: producer: configuration: com.example.ProducerLoadBalancerConfig
6. OpenFeign + Ribbon
✅ 是否基于服务名:✅ 是(自动)
✅ 是否需要
@LoadBalanced:❌ 否✅ 示例代码:
java@FeignClient(name = "producer") public interface MemberFeignClient { @GetMapping("/getMember") String getMember(); } @RestController public class OrderController { @Autowired private MemberFeignClient memberFeignClient; @GetMapping("/orderToMember") public String orderToMember() { return memberFeignClient.getMember(); } } @Configuration public class RibbonConfig { @Bean public IRule ribbonRule() { return new RandomRule(); } }
7. OpenFeign + Spring Cloud LoadBalancer
✅ 是否基于服务名:✅ 是(自动)
✅ 是否需要
@LoadBalanced:❌ 否✅ 示例代码:
java@FeignClient(name = "producer") public interface MemberFeignClient { @GetMapping("/getMember") String getMember(); } @RestController public class OrderController { @Autowired private MemberFeignClient memberFeignClient; @GetMapping("/orderToMember") public String orderToMember() { return memberFeignClient.getMember(); } } // application.yml: spring: cloud: loadbalancer: clients: producer: configuration: com.example.ProducerLoadBalancerConfig随机策略方式同上使用
ReactorLoadBalancer。
8. 总结对比表格
方式 基于服务名 需要 @LoadBalanced 策略配置方式 是否推荐 RestTemplate + 自定义负载均衡 否 否 手动逻辑(如随机) ✅ 灵活 RestTemplate + Ribbon(非服务名) 否 否 IRule/RandomRule⚠️不常见 RestTemplate + Spring Cloud LB(非服务名) 否 否 ReactorLoadBalancer⚠️一般用服务名 RestTemplate + Ribbon(服务名) 是 是 IRule/RandomRule❌ 已弃用 RestTemplate + Spring Cloud LB(服务名) 是 是 ReactorLoadBalancer✅ 推荐 OpenFeign + Ribbon 是 否 IRule/RandomRule❌ 已弃用 OpenFeign + Spring Cloud LB 是 否 ReactorLoadBalancer✅ 推荐 9. 举例说明:是否基于服务名的区别
以RestTemplate + Spring Cloud LoadBalancer + 手动拼接 URL和RestTemplate + Spring Cloud LoadBalancer(基于服务名)为例
1. RestTemplate + Spring Cloud LoadBalancer + 手动拼接 URL
- 通常写法:
java@Bean public RestTemplate restTemplate() { return new RestTemplate(); // 普通RestTemplate,没有@LoadBalanced } @Autowired private LoadBalancerClient loadBalancerClient; public void call() { ServiceInstance instance = loadBalancerClient.choose("service-name"); String url = instance.getUri() + "/api"; restTemplate.getForObject(url, String.class); }
特点:
RestTemplate是普通实例,不支持基于服务名自动负载均衡。你手动通过
LoadBalancerClient获取具体服务实例,再拼完整 URL。负载均衡由
LoadBalancerClient实现,调用时需要自己拼接 URL。
2. RestTemplate + Spring Cloud LoadBalancer(基于服务名)
- 通常写法:
java@Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); // 带@LoadBalanced支持服务名调用 } public void call() { restTemplate.getForObject("http://service-name/api", String.class); }
特点:
RestTemplate通过@LoadBalanced注解支持服务名解析和负载均衡。你直接调用服务名 URL,不用关心具体实例。
负载均衡和服务实例选择完全交给 Spring Cloud LoadBalancer 内部管理。
3. 核心区别总结
特性 手动拼 URL(无 @LoadBalanced) 基于服务名调用(带 @LoadBalanced) RestTemplate是否带 @LoadBalanced否 是 负载均衡策略执行点 LoadBalancerClient手动调用实例选取RestTemplate内部自动调用负载均衡请求时是否需手动拼接 URL 是,需要拼接具体实例的 URI 否,直接写服务名 URL 代码简洁性 代码相对复杂,需要手动管理实例和 URL 代码简洁,专注业务调用 适用场景 需要自定义实例选择或做扩展时使用 绝大多数场景推荐使用
4. 结论
是否加了
@LoadBalanced是两种方式最主要的区别,但真正关键是:
带
@LoadBalanced的RestTemplate支持直接用服务名调用,负载均衡自动执行;不带
@LoadBalanced时需要自己用LoadBalancerClient选实例,拼 URL 手动调用。
分布式微服务--万字详解 微服务的各种负载均衡全场景以注意点
你我约定有三2025-08-01 22:43
相关推荐
胡桃夹夹子1 分钟前
存档111111111不会编程的小寒4 分钟前
C++ 中string的用法Wang's Blog18 分钟前
Nestjs框架: 微服务项目工程结构优化与构建方案乐悠小码22 分钟前
Java设计模式精讲---02抽象工厂模式数据的世界0124 分钟前
技术变革:为何C#与.NET是未来的开发方向想搞艺术的程序员30 分钟前
Go Error 全方位解析:原理、实践、扩展与封装向上的车轮31 分钟前
Actix Web适合什么类型的Web应用?可以部署 Java 或 .NET 的应用程序?GM_82836 分钟前
初识DDD架构脸大是真的好~40 分钟前
黑马JAVAWeb-03 SpringBootWeb-分层解耦-三层架构-@SpringBootApplication注解-IOC控制反转-DI依赖注入微露清风1 小时前
系统性学习C++-第十讲-stack 和 quene