本篇是Spring Cloud Alibaba微服务系列第三篇,主要关于Nacos的服务发现机制。笔者将实践应用三大核心API:@EnableDiscoveryClient、DiscoveryClient和NacosDiscoveryClient,并通过完整代码示例展示如何在实际项目中应用它们。
一、三大核心API详解
1. @EnableDiscoveryClient - 服务发现开关
作用:声明当前应用需要启用服务发现功能
位置:Spring Boot启动类
package top.strarry.product;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
}注意事项:
- Spring Cloud 2020版本后无需显式添加(在编写启动类的时候并没有加上注解,但服务成功启动。总结就是有依赖就行)
- 保留注解可提高代码可读性
- 支持自定义服务注册行为:
@EnableDiscoveryClient(autoRegister = false) // 禁用自动注册2. DiscoveryClient - 通用服务发现接口
核心方法:
List<String> getServices():获取所有注册服务名称List<ServiceInstance> getInstances(String serviceId):获取指定服务的实例列表
@SpringBootTest
public class DiscoveryTest {
@Autowired
DiscoveryClient discoveryClient;
@Test
void discoveryClientTest() {
List<String> services = discoveryClient.getServices();
for (String serviceName : services) {
System.out.println(\"service\" + serviceName);
List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
//获取ip+port
for (ServiceInstance instance : instances) {
System.out.println(instance.getHost() + \":\" + instance.getPort());
}
}
}
}
3. NacosDiscoveryClient - 增强功能实现
特有功能:
- 获取服务的健康状态
- 查询集群信息
- 基于元数据的复杂查询
- 服务订阅机制
@SpringBootTest
public class DiscoveryTest {
@Autowired
NacosDiscoveryClient nacosDiscoveryClient;
@Test
public void nacosDiscoveryClientTest() {
List<String> services = nacosDiscoveryClient.getServices();
for (String service : services) {
System.out.println(\"service = \" + service);
List<ServiceInstance> instances = nacosDiscoveryClient.getInstances(service);
for (ServiceInstance instance : instances) {
System.out.println(\"instance.getHost() = \" + instance.getHost());
System.out.println(\"instance.getPort() = \" + instance.getPort());
}
}
}
}
二者运行结果均一致:

二、远程调用
1.编写Order订单实体类
@Data
public class Order {
private Long id;
private BigDecimal totalAmount;
private Long userId;
private String nickname;
private String address;
private List<Product> productList;
}2.编写Product商品实体类
@Data
public class Product {
private Long id;
private BigDecimal price;
private String productName;
private int num;
}3.编写创建订单接口
@RestController
public class OrderController {
@Autowired
OrderService orderService;
@GetMapping(\"/create\")
public Order createOrder(@RequestParam(\"userId\") Long userId,
@RequestParam(\"productId\") Long productId) {
Order order = orderService.createOrder(userId, productId);
return order;
}
}
4.编写创建订单服务接口
@Service
public interface OrderService {
Order createOrder(Long productId, Long userId);
}5.编写创建订单服务实现类
@Service
public class OrderServiceImpl implements OrderService {
@Override
public Order createOrder(Long userId, Long productId) {
Order order = new Order();
order.setId(1L);
//TODO 总金额
order.setTotalAmount(new BigDecimal(\"0\"));
order.setUserId(userId);
order.setNickName(\"张三\");
order.setAddress(\"北京\");
//TODO 远程查询商品列表
order.setProductList(null);
return order;
}
}
6.编写商品接口
@RestController
public class ProductController {
@Autowired
ProductService productService;
@GetMapping(\"/product/{id}\")
public Product getProduct(@PathVariable(\"id\") Long productId) {
Product product = productService.getProductById(productId);
return product;
}
}7.编写商品服务接口
@Service
public interface ProductService {
Product getProductById(Long productId);
}8.编写商品服务实现类
@Service
public class ProductServiceImpl implements ProductService {
@Override
public Product getProductById(Long productId) {
Product product = new Product();
product.setId(productId);
product.setPrice(new BigDecimal(\"99\"));
product.setProductName(\"苹果\");
product.setNum(2);
return product;
}
}
9.测试接口
测试商品接口:http://localhost:9000/product/2,返回如下:
{
\"id\": 2,
\"price\": 99,
\"productName\": \"苹果\",
\"num\": 2
}
测试订单接口:http://localhost:8000/create?userId=2&productId=23,返回如下:
{
\"id\": 1,
\"totalAmount\": 198,
\"userId\": 23,
\"nickname\": \"zhangsan\",
\"address\": \"hebei\",
\"productList\": [
{
\"id\": 2,
\"price\": 99,
\"productName\": \"苹果\",
\"num\": 2
}
]
}
三、远程调用
1.常见的远程调用对比
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| RestTemplate | 灵活可控,简单直接 | 需要手动拼接URL | 简单调用,快速原型 |
| OpenFeign | 声明式编程,自动生成实现类 | 学习曲线较陡 | 标准RESTful接口调用 |
| WebClient | 响应式非阻塞,高性能 | 异步编程模型复杂 | 高并发,响应式系统 |
2.实现订单的远程调用
①将RestTemplate注册到spring容器
@Configuration
public class OrderConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}②编写订单的远程调用实现类
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
DiscoveryClient discoveryClient;
@Autowired
RestTemplate restTemplate;
@Override
public Order createOrder(Long productId, Long userId) {
Product productFromRemot = getProductFromRemote(productId);
Order order = new Order();
//TODO 总金额
order.setTotalAmount(productFromRemot.getPrice().multiply(new BigDecimal(productFromRemot.getNum())));
order.setId(1L);
order.setUserId(userId);
order.setNickname(\"zhangsan\");
order.setAddress(\"hebei\");
//TODO 远程查询商品列表
order.setProductList(Arrays.asList(productFromRemot ));
return order;
}
//1.发送请求
private Product getProductFromRemote(Long productId) {
//1、获取商品服务所在的所有机器IP+Port
List<ServiceInstance> instances = discoveryClient.getInstances(\"service-product\");
ServiceInstance serviceInstance = instances.get(0);
//2.拼接远程url
String url = \"http://\"+serviceInstance.getHost()+\":\"+ serviceInstance.getPort()+\"/product/\"+productId;
log.info(\"远程请求路径:{}\",url);
//3.发送远程请求
Product forObject = restTemplate.getForObject(url, Product.class);
return forObject;
}
}
3.测试接口
测试远程调用:http://localhost:8000/create?userId=2&productId=1,返回内容如下:
{
\"id\": 1,
\"totalAmount\": 198,
\"userId\": 23,
\"nickname\": \"zhangsan\",
\"address\": \"hebei\",
\"productList\": [
{
\"id\": 2,
\"price\": 99,
\"productName\": \"苹果\",
\"num\": 2
}
]
}
控制台打印出远程调用所拼接的URL地址信息:

四、总结
本次我们深入探讨了Nacos服务发现的三大核心API:
@EnableDiscoveryClient- 服务发现的开关- 声明式启用服务发现
- 支持自定义注册行为
- 新版本可自动启用
DiscoveryClient- 通用服务发现接口- 获取服务列表和实例信息
- 与Spring Cloud标准集成
- 支持元数据查询
NacosDiscoveryClient- 增强实现- 获取Nacos特有信息
- 支持服务订阅机制
- 提供高级查询能力
下一步回顾:
[Nacos配置中心]
[OpenFeign声明式调用]
评论