You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过@LoadBalanced实现Eureka服务名到地址映射(无需DiscoveryClient)

问题:无法通过@LoadBalanced注解隐式映射Eureka注册的服务名

我想在不使用DiscoveryService的情况下,通过服务名调用已注册到Eureka的服务。原本以为只要给RestTemplate添加@LoadBalanced注解,就能自动把服务名映射到对应的主机端口,直接用应用名称发起请求就行,但实际没生效。

请求方微服务代码

配置类

@Configuration
public class Config {
    @Bean
    @LoadBalanced // 已添加该注解
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
        return restTemplateBuilder.build();
    }
}

业务服务类

@Service
@RequiredArgsConstructor
public class PlanetService {
    private final RestTemplate restTemplate;
    public Planet getPlanet(String name) {
        return restTemplate.getForObject("http://planet_ms/api/planets?name=" + name, Planet.class);
    }
}

响应方微服务代码

控制器类

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class PlanetController {
    private final PlanetService planetService;
    @GetMapping("/planets")
    public Planet getPlanet(@RequestParam String name) {
        return planetService.getPlanet(name);
    }
}

配置文件

server.port=8081
spring.application.name=planet_ms

手动通过DiscoveryClient获取实例并拼接地址的方式可以正常工作,但我更倾向于@LoadBalanced提供的隐式映射方式,不想手动处理主机和端口。我想知道:为什么@LoadBalanced不生效?

// 该方式可以正常调用
@Service
@RequiredArgsConstructor
public class PlanetService {
    private final RestTemplate restTemplate;
    private final DiscoveryClient discoveryClient;
    public Planet getPlanet(String name) {
        var planetMicroservice = discoveryClient.getInstances("planet_ms").get(0);
        String host = planetMicroservice.getHost();
        int port = planetMicroservice.getPort();
        return restTemplate.getForObject(format("http://%s:%d/api/planets?name=%s", host, port, name), Planet.class);
    }
}

更新:尝试修改后仍报错

我按照建议做了以下修改:

  1. 将服务名的下划线替换为连字符
spring.application.name=planet-ms
  1. 添加Spring Cloud LoadBalancer依赖
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    <version>4.0.4</version>
</dependency>
  1. 在RestTemplate的Bean定义和构造函数注入时都添加@LoadBalanced注解
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
    return restTemplateBuilder.build();
}
public PlanetService(@LoadBalanced RestTemplate restTemplate) {
    this.restTemplate = restTemplate;
}

public Planet getPlanet(String name) {
    return restTemplate.getForObject("http://planet-ms/api/planets?name=" + name,
            Planet.class);
}

修改后出现以下错误:

WARN 15492 --- [nio-8080-exec-1] o.s.c.l.core.RoundRobinLoadBalancer      : No servers available for service: host.docker.internal

我没有使用Docker,且响应方微服务已经正常运行:
运行中的微服务


解决方案

1. 确认Eureka集成配置

Spring Cloud LoadBalancer需要和Eureka正确集成才能拉取服务实例。确保请求方微服务已引入Eureka客户端依赖,并配置正确的注册中心地址:

# 请求方application.properties
eureka.client.service-url.defaultZone=http://你的Eureka地址:端口/eureka/
eureka.client.fetch-registry=true # 显式开启拉取注册列表,默认值为true,但建议明确配置

2. 修复host.docker.internal解析错误

这个错误是LoadBalancer在部分环境下的默认行为导致的,即使未使用Docker也会触发。可以通过配置强制LoadBalancer从Eureka获取实例:

spring.cloud.loadbalancer.discovery.enabled=true
# 或者直接禁用Docker相关服务发现
spring.cloud.loadbalancer.docker.enabled=false

3. 校验服务名一致性

确保请求方使用的服务名planet-ms和响应方注册到Eureka的名称完全一致,注意大小写(Eureka默认服务名小写,建议配置时统一格式)。

4. 验证RestTemplate拦截器

调试确认注入的RestTemplate是否包含LoadBalancerInterceptor,这是负载均衡生效的核心。如果存在多个RestTemplate Bean,要确保注入的是带有@LoadBalanced注解的实例(你已在构造函数上添加注解,此步骤大概率没问题,但可验证)。

5. 检查版本兼容性

Spring Cloud LoadBalancer 4.0.4对应Spring Cloud 2022.0.x(Kilburn)版本,需确保Spring Boot版本为3.0.x或3.1.x,避免版本冲突导致功能异常。


内容的提问来源于stack exchange,提问作者Sergey Zolotarev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 20:05:14