本文目录导读:

我来为你提供一个完整的Spring Cloud Nacos服务发现案例,包含服务提供者和服务消费者。
项目结构
nacos-discovery-demo
├── pom.xml (父POM)
├── user-service (服务提供者)
└── order-service (服务消费者)
父POM配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>nacos-discovery-demo</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
</properties>
<modules>
<module>user-service</module>
<module>order-service</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
服务提供者 (user-service)
1 POM配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>nacos-discovery-demo</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>user-service</artifactId>
<name>user-service</name>
<description>用户服务提供者</description>
<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Nacos Config (可选) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Actuator 健康检查 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
2 主启动类
package com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
System.out.println("用户服务启动成功!");
}
}
3 配置文件 application.yml
server:
port: 8081
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
# 命名空间ID(可选,默认public)
namespace: public
# 集群名称(可选)
# cluster-name: DEFAULT
# 权重(默认1.0)
weight: 1.0
# 是否注册服务(默认true)
register-enabled: true
# 是否心跳检测
heart-beat-interval: 5000
heart-beat-timeout: 15000
ip-delete-timeout: 30000
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
group: DEFAULT_GROUP
# 支持多个配置
shared-configs:
- data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
# 日志配置
logging:
level:
com.alibaba.nacos: warn
com.example: debug
# 管理端点
management:
endpoints:
web:
exposure:
include: '*'
4 实体类
package com.example.userservice.entity;
public class User {
private Long id;
private String username;
private String email;
private Integer age;
public User() {}
public User(Long id, String username, String email, Integer age) {
this.id = id;
this.username = username;
this.email = email;
this.age = age;
}
// Getter和Setter方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
5 Controller
package com.example.userservice.controller;
import com.example.userservice.entity.User;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@RestController
@RequestMapping("/api/users")
@RefreshScope
public class UserController {
private static final Logger log = LoggerFactory.getLogger(UserController.class);
@Value("${server.port}")
private String serverPort;
@Value("${test.config:默认配置}") // 从Nacos配置中心读取
private String testConfig;
// 模拟数据库
private static final Map<Long, User> userMap = new ConcurrentHashMap<>();
static {
userMap.put(1L, new User(1L, "张三", "zhangsan@example.com", 25));
userMap.put(2L, new User(2L, "李四", "lisi@example.com", 28));
userMap.put(3L, new User(3L, "王五", "wangwu@example.com", 32));
}
@GetMapping
public List<User> getAllUsers() {
List<User> users = new ArrayList<>(userMap.values());
log.info("从端口 {} 获取用户列表,数量:{}", serverPort, users.size());
return users;
}
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
User user = userMap.get(id);
log.info("从端口 {} 获取用户:{}", serverPort, user);
return user;
}
@PostMapping
public User createUser(@RequestBody User user) {
user.setId(System.currentTimeMillis());
userMap.put(user.getId(), user);
log.info("从端口 {} 创建用户:{}", serverPort, user);
return user;
}
@GetMapping("/info")
public String getServerInfo() {
return "当前服务实例端口:" + serverPort + ",配置信息:" + testConfig;
}
}
5b 负载均衡测试接口
package com.example.userservice.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/health")
public class HealthController {
@Value("${server.port}")
private String serverPort;
@GetMapping
public String health() {
return "User Service instance on port " + serverPort + " is healthy!";
}
}
服务消费者 (order-service)
1 POM配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>nacos-discovery-demo</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>order-service</artifactId>
<name>order-service</name>
<description>订单服务消费者</description>
<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- OpenFeign 服务调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- LoadBalancer 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- Actuator 健康检查 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
2 主启动类
package com.example.orderservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
System.out.println("订单服务启动成功!");
}
}
3 配置文件 application.yml
server:
port: 8082
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: public
register-enabled: true
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
loadbalancer:
nacos:
enabled: true # 使用Nacos负载均衡策略
# Ribbon负载均衡配置(可选)
ribbon:
nacos:
enabled: true
ConnectTimeout: 5000
ReadTimeout: 5000
# Feign配置
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
logging:
level:
com.example.orderservice.client: debug
4 使用OpenFeign的定义
package com.example.orderservice.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "user-service") // 通过服务名调用
public interface UserClient {
@GetMapping("/api/users/{id}")
Object getUserById(@PathVariable Long id);
@GetMapping("/api/users")
Object getAllUsers();
@GetMapping("/health")
String getHealth();
}
5 使用RestTemplate + @LoadBalanced
package com.example.orderservice.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced // 开启负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
6 Service层
package com.example.orderservice.service;
import com.example.orderservice.client.UserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@Service
public class OrderService {
@Autowired
private UserClient userClient;
@Autowired
private RestTemplate restTemplate;
/**
* 通过Feign调用服务
*/
public Object getUserByFeign(Long userId) {
return userClient.getUserById(userId);
}
/**
* 通过RestTemplate调用服务
*/
public Object getUserByRestTemplate(Long userId) {
String url = "http://user-service/api/users/" + userId;
return restTemplate.getForObject(url, Object.class);
}
/**
* 获取所有用户(Feign)
*/
public Object getAllUsersByFeign() {
return userClient.getAllUsers();
}
/**
* 获取所有用户(RestTemplate)
*/
public Object getAllUsersByRestTemplate() {
String url = "http://user-service/api/users";
return restTemplate.getForObject(url, Object.class);
}
/**
* 获取用户服务健康状态
*/
public String getUserServiceHealth() {
return userClient.getHealth();
}
}
7 Controller
package com.example.orderservice.controller;
import com.example.orderservice.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private static final Logger log = LoggerFactory.getLogger(OrderController.class);
@Autowired
private OrderService orderService;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/users/{userId}")
public Map<String, Object> getUserInfo(@PathVariable Long userId) {
Map<String, Object> result = new HashMap<>();
// 通过Feign调用
Object feignData = orderService.getUserByFeign(userId);
// 通过RestTemplate调用
Object restTemplateData = orderService.getUserByRestTemplate(userId);
result.put("feignData", feignData);
result.put("restTemplateData", restTemplateData);
return result;
}
@GetMapping("/users/all")
public Map<String, Object> getAllUsers() {
Map<String, Object> result = new HashMap<>();
result.put("feignAllUsers", orderService.getAllUsersByFeign());
result.put("restTemplateAllUsers", orderService.getAllUsersByRestTemplate());
return result;
}
@GetMapping("/discovery")
public List<ServiceInstance> discoverServices() {
return discoveryClient.getInstances("user-service");
}
@GetMapping("/health")
public String getUserServiceHealth() {
return orderService.getUserServiceHealth();
}
}
8 服务发现控制器
package com.example.orderservice.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/services")
public class ServiceDiscoveryController {
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping
public Map<String, Object> getAllServices() {
Map<String, Object> result = new HashMap<>();
List<String> services = discoveryClient.getServices();
result.put("services", services);
for (String service : services) {
List<ServiceInstance> instances = discoveryClient.getInstances(service);
List<Map<String, Object>> instanceInfo = new ArrayList<>();
for (ServiceInstance instance : instances) {
Map<String, Object> info = new HashMap<>();
info.put("serviceId", instance.getServiceId());
info.put("host", instance.getHost());
info.put("port", instance.getPort());
info.put("uri", instance.getUri());
info.put("instanceId", instance.getInstanceId());
info.put("metadata", instance.getMetadata());
instanceInfo.add(info);
}
result.put(service, instanceInfo);
}
return result;
}
@GetMapping("/{serviceName}")
public List<ServiceInstance> getServiceInstances(@PathVariable String serviceName) {
return discoveryClient.getInstances(serviceName);
}
}
启动和测试
1 环境准备
下载并启动Nacos Server
# Linux/Mac sh startup.sh -m standalone # Windows startup.cmd -m standalone
访问Nacos控制台
- 地址:http://127.0.0.1:8848/nacos
- 默认账号密码:nacos/nacos
2 启动服务
# 启动用户服务 cd user-service mvn spring-boot:run # 启动订单服务 cd order-service mvn spring-boot:run
3 测试API
# 1. 测试服务发现 curl http://localhost:8082/services # 2. 测试通过Feign调用用户服务 curl http://localhost:8082/api/orders/users/1 # 3. 测试通过RestTemplate调用用户服务 curl "http://localhost:8082/api/orders/users/all" # 4. 获取用户服务健康状态 curl http://localhost:8082/api/orders/health # 5. 直接调用用户服务 curl http://localhost:8081/api/users/1
4 负载均衡测试
启用多个user-service实例测试负载均衡:
# 启动多个用户服务实例(不同端口)
mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=8083
mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=8084
# 多次调用观察负载均衡效果
for i in {1..5}; do
curl http://localhost:8082/api/orders/health
echo ""
done
Nacos控制台配置(可选)
1 配置中心配置
在Nacos控制台创建数据ID:order-service.yaml
# 订单服务配置 order: timeout: 3000 auto-confirm: true # 自定义配置 test: config: 这是从Nacos配置中心读取的配置
2 配置项说明
# 服务发现配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos服务器地址
namespace: public # 命名空间
group: DEFAULT_GROUP # 分组
weight: 1.0 # 权重,范围0-10000
register-enabled: true # 是否注册
ip: 127.0.0.1 # 指定IP(可选)
port: 8081 # 指定端口(可选)
metadata: # 元数据
version: 1.0
region: cn-hangzhou
常见配置示例
1 集群环境配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848,127.0.0.2:8848,127.0.0.3:8848
namespace: prod-namespace
cluster-name: HANGZHOU
2 多环境配置
# bootstrap.yml
spring:
profiles:
active: dev
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: ${spring.profiles.active}
注意事项
- 版本兼容性:注意Spring Boot、Spring Cloud和Spring Cloud Alibaba的版本对应关系
- 服务命名:服务名只能使用小写字母、数字和连字符
- 防火墙配置:确保8848端口可以访问
- 集群环境:生产环境建议使用集群部署
- 安全性:可以配置Nacos的认证和权限控制
这个案例展示了Nacos服务发现的核心功能,包括服务注册、发现、调用和负载均衡,你可以根据实际需求进行扩展和调整。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播