目录
1. 服务消费者启动类
1.1. 服务消费者 controller
2. 服务提供者启动类
2.1. 服务提供者 controller
3. 服务报错
4. nacos 信息
5. 解决思路
5.1. 配置、注解检查
5.2. 其他方面原因排查
6. 解决方案
7. 参考连接
在 SpringBoot 项目中调用另外的服务报错:
重点是这一句:
java.net.UnknownHostException: stock-nacos
意思是未知的主机异常:stock-nacos
stock-nacos 是被调用方。
项目架构如下:
框架 | 版本号 |
Spring Boot | 2.6.3 |
spring.cloud.alibaba |
2021.0.1.0 |
spring.cloud |
2021.0.1 |
采用 RestTemplate 进行服务之间的调用,配置负载均衡注解,代码如下:
package com.dake.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
// 在spring cloud 现在的新版本中不需要添加了
@EnableDiscoveryClient
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
// 通常写在配置类中,但是示例的话就这样也可以
// LoadBalanced注解是告诉该服务调用对方服务时使用负载均衡策略调用,没有此注解则调用时会报500的错误响应码
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
// public RestTemplate restTemplate(RestTemplateBuilder builder ) {
// 可以 new RestTemplate,但是官方推荐 RestTemplateBuilder 构造器來构造,提现了构造者模式的设计思想
// 在这里可以设置超时时间等属性,这里先不设置
return new RestTemplate();
// return builder.build();
}
}
package com.dake.order.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
private String serviceUrl;
@Value("${server.port}")
private String port;
@RequestMapping("/add")
public String add() {
// String msg = restTemplate.getForObject("http://localhost:8021" + "/stock/reduct", String.class);
String msg = restTemplate.getForObject(serviceUrl + "/stock/reduct", String.class);
System.out.println("---------下单成功---------");
return "Hello World " + msg + ":" + port;
}
}
package com.dake.stock;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class StockApplication {
public static void main(String[] args) {
SpringApplication.run(StockApplication.class, args);
}
}
package com.dake.stock.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/stock")
public class StockController {
@RequestMapping("/reduct")
public String reduct() {
System.out.println("---------扣减库存---------");
return "扣减库存";
}
}
通过 URL 调用服务消费者的 controller 报错:
报错信息,参见文章开头。
我们 nacos 配置完成,1个服务消费者实例和2个服务提供者实例均已注册到 nacos 中。
关于 nacos 的配置检查完毕,没有发现有问题。
我们要看是否缺少了注解、配置,或者配置错误,检查完毕之后没有发现有什么问题。
有文章说需要在 RestTemplate 上添加 @LoadBalanced 注解。如果我们去看我的服务消费者启动类,就会发现,该注解我们是有的。
还有人说是 需要在启动类上添加注解 @EnableDiscoveryClient 。实际上,在新版本的 Spring Cloud Alibaba 中,该注解不使用一样可以实现服务注册与发现功能。我们在下文会演示不添加该注解是否可以自动实现服务注册于发现。
到了这里,还是解决不了问题。此时不得不去考虑,是否是 SpringBoot版本、 Spring Cloud 与 Spring Cloud Alibaba 版本兼容问题。通过官网我们发现我们使用的版本兼容性没有问题,我们也不用去想我们发现了什么 bug 之类的奇思妙想。
还有人说是 JDK 版本兼容问题。这个有可能,我使用的是 JDK 17,这个倒是有可能,但是我将 JDK 版本降低之后发现还是同样的错误。
我们排除了各种原因之后,还是解决不了问题,那这个可能就麻烦了。
我通过翻看自己之前的项目,也去网上找了 Spring Cloud Alibaba 的教程,也没有发现问题。
就这样,没有办法了,这个项目的演示就耽搁这里了。
过了一阵子,我回头继续看这个问题,还是同样的错误。但是这次我们尝试了不同的检索方式,最终让我找到了一个解决方案:
在服务消费方的 pom 文件中添加依赖:
org.springframework.cloud
spring-cloud-starter-loadbalancer
找到的参考文章中没有提到在服务消费者还是服务提供者的 pom 中添加该依赖,我个人感觉应该是服务消费者 ,因为它添加的是负载均衡的依赖,而 nacos 自带的 Ribbon 是一个客户端负载均衡,意思就是谁调用就谁来决定负载均衡策略。当然还有服务端负载均衡策略,如F5、HA等,这不在本文的讨论范围,感兴趣者可以自行查阅资料。
我门就在服务消费者的 pom 中添加了以上依赖,刚开始可能是项目编译问题,没有成功,我将服务提供者的 pom 中也添加了该依赖,重新编译后调用成功了。但是这里我们不清楚真正加在哪里,我们去除了 服务消费者的该依赖,结果调用失败。这也证明了是需要添加在 服务消费者的pom 中。但是,这不一定正确,因为我们之前也在服务提供者中也添加了该依赖,下面我们去除服务提供者中的依赖,最终如图:
启动项目,重新调用,成功:
Spring Cloud:负载均衡 - Spring Cloud Loadbalancer原理
(已解决)nacos+RestTemplate使用服务名报异常java.net.UnknownHostException