[spring cloud] nacos注册中心和配置中心

1. Nacos 作为服务注册中心 (Service Registry)

1.1 核心原理

Nacos 作为注册中心,主要维护一张"服务列表"。

  1. 服务注册 (Registration): 服务提供者(Provider)启动时,会通过 REST API 发送请求向 Nacos Server 注册自己的信息(IP、端口、服务名)。
  2. 心跳机制 (Heartbeat): 提供者会定时(默认 5 秒)发送心跳包。如果 Nacos 超过 15 秒没收到心跳,会将实例设为不健康;超过 30 秒则剔除。
  3. 服务发现 (Discovery): 服务消费者(Consumer)从 Nacos 拉取服务列表,并缓存在本地。
  4. 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 提供了集中式管理和动态刷新。

  1. Data ID: Nacos 组织配置的核心,通常格式为 ${spring.application.name}-${spring.profiles.active}.${file-extension} (例如 services-order-dev.yaml)。
  2. 长轮询 (Long Polling): 客户端不单纯是拉取配置。客户端会发起一个长连接请求,Nacos 收到请求后若配置无变化会 hold 住请求(默认 30秒),一旦配置发生变化,立即返回最新配置。这保证了配置更新的实时性。
  3. 动态刷新: 结合 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 控制台添加配置

  1. 登录 Nacos 控制台。
  2. 进入"配置管理 -> 配置列表"。
  3. 点击"+"号新增配置:
  • 新建命名空间
  • Group: 填 order
  • Data ID: common.properties (必须与上面 import 的逻辑匹配)
  • 配置格式: Properties
  • 配置内容:
Properties 复制代码
# 订单超时时间
order.timeout=5000
  1. 发布。

第四步: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 配置中心进阶使用的两个重要场景。

  1. @ConfigurationProperties :属于 Spring Boot 原生方式 。用于将一组配置批量绑定到 Java Bean 中。在 Spring Cloud 环境下,它自带"自动刷新"光环,比 @Value 更强大、更优雅。
  2. 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;
    }
}

实操验证

  1. 启动服务,访问 /props,看到 connectTimeout 是 2000。
  2. 在 Nacos 控制台修改为 9999,发布。
  3. 不用重启 ,再次访问 /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;
    }
}
相关推荐
shuair5 小时前
redis缓存预热、缓存击穿、缓存穿透、缓存雪崩
redis·spring·缓存
计算机程序设计小李同学5 小时前
基于 Spring Boot + Vue 的龙虾专营店管理系统的设计与实现
java·spring boot·后端·spring·vue
Charlie_lll7 小时前
力扣解题-[3379]转换数组
数据结构·后端·算法·leetcode
qq_12498707537 小时前
基于Java Web的城市花园小区维修管理系统的设计与实现(源码+论文+部署+安装)
java·开发语言·前端·spring boot·spring·毕业设计·计算机毕业设计
VX:Fegn08958 小时前
计算机毕业设计|基于springboot + vue云租车平台系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
岁岁种桃花儿8 小时前
SpringCloud从入门到上天:Nacos做微服务注册中心
java·spring cloud·微服务
Chasmれ8 小时前
Spring Boot 1.x(基于Spring 4)中使用Java 8实现Token
java·spring boot·spring
汤姆yu8 小时前
2026基于springboot的在线招聘系统
java·spring boot·后端
计算机学姐8 小时前
基于SpringBoot的校园社团管理系统
java·vue.js·spring boot·后端·spring·信息可视化·推荐算法
落霞的思绪8 小时前
Spring AI Alibaba 集成 Redis 向量数据库实现 RAG 与记忆功能
java·spring·rag·springai