1. Nacos 作为服务注册中心 (Service Registry)
1.1 核心原理
Nacos 作为注册中心,主要维护一张"服务列表"。
- 服务注册 (Registration): 服务提供者(Provider)启动时,会通过 REST API 发送请求向 Nacos Server 注册自己的信息(IP、端口、服务名)。
- 心跳机制 (Heartbeat): 提供者会定时(默认 5 秒)发送心跳包。如果 Nacos 超过 15 秒没收到心跳,会将实例设为不健康;超过 30 秒则剔除。
- 服务发现 (Discovery): 服务消费者(Consumer)从 Nacos 拉取服务列表,并缓存在本地。
- CAP 理论: Nacos 支持 AP (可用性优先,默认) 和 CP (一致性优先) 模式的切换。
1.注册 & 发送心跳
2.订阅 & 拉取列表
3.推送变更
4.远程调用(RPC/REST)
服务提供者 Provider
Nacos Server
服务消费者 Consumer
1.2 Java 代码实战 (Spring Boot 3.0+)
第一步:引入依赖 (pom.xml)
在使用 Spring Boot 3.x 时,需配合 Spring Cloud Alibaba 2022.0.0.0 或更高版本。
xml
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
第二步:配置文件 (application.yml)
yaml
server:
port: 8081
spring:
application:
name: nacos-provider-demo # 服务名称,非常重要
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos Server 地址
第三步:启动类与测试
Spring Boot 3.x 中,@EnableDiscoveryClient 注解由自动化配置处理,通常不再需要显式添加,但写上也无妨。
java
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
启动后,在 Nacos 控制台的"服务管理 -> 服务列表"中即可看到 nacos-provider-demo。
2. Nacos 作为配置中心 (Config Center)
2.1 核心原理
在微服务架构中,几十个服务的配置文件如果都散落在 Jar 包里,修改配置需要重启,非常麻烦。Nacos 提供了集中式管理和动态刷新。
- Data ID: Nacos 组织配置的核心,通常格式为
${spring.application.name}-${spring.profiles.active}.${file-extension}(例如services-order-dev.yaml)。 - 长轮询 (Long Polling): 客户端不单纯是拉取配置。客户端会发起一个长连接请求,Nacos 收到请求后若配置无变化会 hold 住请求(默认 30秒),一旦配置发生变化,立即返回最新配置。这保证了配置更新的实时性。
- 动态刷新: 结合 Spring 的
@RefreshScope,可以在不重启应用的情况下更新内存中的变量。
2.2 Java 代码实战 (Spring Boot 3.0+ 重点)
第一步:引入依赖
在之前的 pom.xml 基础上添加:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
第二步:配置文件 (application.yml)
直接在 application.yml 中使用 import 语法。
yml
spring:
profiles:
active: dev
application:
name: service-order
cloud:
nacos:
server-addr: 127.0.0.1:8848
config:
import-check:
enabled: false
namespace: ${spring.profiles.active:dev} #指定命名空间
server:
port: 8080
---
spring:
config:
import:
- nacos:common.properties?group=order # nacos:{DataId}?group={Group}
activate:
on-profile: dev
---
spring:
config:
import:
- nacos:common.properties?group=order
activate:
on-profile: prod
第三步:在 Nacos 控制台添加配置
- 登录 Nacos 控制台。
- 进入"配置管理 -> 配置列表"。
- 点击"+"号新增配置:
- 新建命名空间
- Group: 填 order
- Data ID:
common.properties(必须与上面 import 的逻辑匹配) - 配置格式: Properties
- 配置内容:
Properties
# 订单超时时间
order.timeout=5000
- 发布。
第四步:Java 代码读取与动态刷新
为了演示不重启更新配置,我们需要使用 @RefreshScope。
java
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope // 关键注解:当 Nacos 配置变更时,动态刷新此类中的 @Value 属性
public class ConfigController {
@Value("${user.name}")
private String userName;
@Value("${user.age}")
private Integer userAge;
@GetMapping("/config/info")
public String getConfigInfo() {
return "User: " + userName + ", Age: " + userAge;
}
}
3. 配置优先级
在 Spring Boot 3 + Nacos 中,配置的加载是有严格顺序的。原则是:"越具体,优先级越高"。
假设服务名是 service-order,环境是 dev。以下是配置生效的优先级(从高到低,上面的覆盖下面的):
| 优先级 | 配置文件 (Data ID) | 说明 |
|---|---|---|
| NO.1 (最高) | service-order-dev.yaml |
精确匹配:既指定了服务名,又指定了环境 profile。这是主配置。 |
| NO.2 | service-order.yaml |
服务默认:只指定了服务名,没指定环境。通常放该服务所有环境通用的配置。 |
| NO.3 | common.properties (import) |
扩展/共享配置 :通过 spring.config.import 引入的外部配置。 |
| NO.4 (最低) | 本地 application.yml |
项目 Jar 包里的本地配置。 |
这两个是 Nacos 配置中心进阶使用的两个重要场景。
@ConfigurationProperties:属于 Spring Boot 原生方式 。用于将一组配置批量绑定到 Java Bean 中。在 Spring Cloud 环境下,它自带"自动刷新"光环,比@Value更强大、更优雅。NacosConfigManager监听 :属于 Nacos SDK 底层方式 。当你不仅仅想更新变量,还想在配置变化时触发一段业务逻辑(比如:清理本地缓存、调整线程池大小、打印日志),就需要用到它。
下面我基于 Spring Boot 3.0+ 为你详细介绍原理和代码。
4. @ConfigurationProperties 批量绑定与自动刷新
4.1 原理
- 批量绑定 :Spring Boot 通过扫描
prefix前缀,将配置文件(Nacos 里的 YAML/Properties)中的值自动映射到 Bean 的属性上。 - 自动刷新:
- 这与
@Value不同。使用@Value必须加@RefreshScope才能动态刷新。 - 使用
@ConfigurationProperties的 Bean,Spring Cloud 有一个专门的ConfigurationPropertiesRebinder监听器。当 Nacos 配置发生变化发出RefreshEvent时,这个监听器会自动销毁旧 Bean,重新绑定生成新 Bean。
4.2 Java 代码实战
场景 :我们在 Nacos 的 service-order-dev.yaml 中配置了一组订单的超时规则。
Nacos 配置内容:
yaml
order:
rules:
connect-timeout: 2000
read-timeout: 5000
auto-confirm-days: 7
Java 代码 (OrderProperties.java):
java
package com.example.order.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data // 必须要有 Setter 方法,Spring 才能注入值
@Component // 注册为 Spring Bean
@ConfigurationProperties(prefix = "order.rules") // 指定前缀
public class OrderProperties {
/**
* 连接超时时间
* 对应 YAML 中的 order.rules.connect-timeout
*/
private Integer connectTimeout;
/**
* 读取超时时间
*/
private Integer readTimeout;
/**
* 自动确认收货天数
*/
private Integer autoConfirmDays;
}
测试控制器:
java
@RestController
public class TestController {
@Autowired
private OrderProperties orderProperties;
@GetMapping("/props")
public OrderProperties getProps() {
// 直接返回对象,当 Nacos 修改配置后,再次访问这里,值会自动变
return orderProperties;
}
}
实操验证:
- 启动服务,访问
/props,看到connectTimeout是 2000。 - 在 Nacos 控制台修改为 9999,发布。
- 不用重启 ,再次访问
/props,你会发现值已经变成了 9999。
5. NacosConfigManager 监听配置变化
5.1 原理
有时候,配置变了,我们不只是想改变变量的值,我们想执行代码 。
例如:useLocalCache 开关从 true 变成了 false,我不仅要更新变量,我还需要立即清空内存里的 Map。这时候仅仅通过注入属性是不够的。
NacosConfigManager 是 Spring Cloud Alibaba 对 Nacos 原生 SDK (ConfigService) 的封装。通过它,我们可以注册一个监听器 (Listener) ,当 Nacos 服务端推送配置变更时,客户端的回调方法 receiveConfigInfo 会被触发。
5.2 Java 代码实战
场景 :监听 common.properties 文件的变化,一旦变化,打印日志并执行自定义逻辑。
java
package com.example.order.listener;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.Executor;
@Slf4j
@Component
public class CustomConfigListener {
@Autowired
private NacosConfigManager nacosConfigManager;
// 假设我们要监听的 DataId 和 Group
private final String dataId = "common.properties";
private final String group = "order";
@PostConstruct
public void init() throws NacosException {
// 获取原生的 ConfigService
nacosConfigManager.getConfigService().addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
// 返回 null 表示使用 Nacos 内部的主线程来执行回调
// 如果逻辑很复杂,建议自定义线程池
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
// configInfo 就是变化后最新的配置内容(字符串形式)
log.info("【监听到配置变化】DataID: {}, Group: {}", dataId, group);
log.info("新配置内容: \n{}", configInfo);
// TODO: 在这里执行你的业务逻辑
// 比如:refreshLocalCache();
// 比如:updateThreadPoolSize();
}
});
}
}
5.3 进阶:监听特定的值 (结合 JSON/YAML 解析)
receiveConfigInfo 返回的是整个文件的字符串。如果你只想监听 timeout 这一项的变化,你需要自己解析字符串。
java
// 伪代码示例
public void receiveConfigInfo(String configInfo) {
Properties props = new Properties();
props.load(new StringReader(configInfo)); // 解析配置
String newTimeout = props.getProperty("timeout");
if (!newTimeout.equals(currentTimeout)) {
log.info("检测到 timeout 发生改变,执行更新逻辑...");
currentTimeout = newTimeout;
}
}