
在微服务架构席卷全球的今天,服务治理成为了每个企业必须跨越的门槛。想象一下:当你的系统从几个服务膨胀到上百个服务,如何高效管理它们的配置?如何让服务之间智能发现并通信?如何在不重启服务的情况下动态调整系统行为?
阿里巴巴给出的答案是 ——Nacos。这个名字源自 "Dynamic Naming and Configuration Service" 的缩写,正如其名,它集服务发现、配置管理于一体,为微服务架构提供了一站式解决方案。
根据 Nacos 官方文档(https://nacos.io/zh-cn/docs/what-is-nacos.html),自 2018 年开源以来,Nacos 已经成为 Spring Cloud Alibaba 生态的核心组件,被阿里巴巴集团内部以及数以万计的企业级应用所采用,支撑着单日数十亿次的服务调用。
本文将带你全面掌握 Nacos 的核心原理与实战技巧,从基础安装到高级特性,从源码解析到最佳实践,让你真正做到融会贯通,在实际项目中得心应手。
Nacos 是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它提供了一组简单易用的特性集,帮助你快速实现动态服务发现、服务配置、服务元数据及流量管理。
用一句话概括 Nacos 的核心价值:"Nacos = 注册中心 + 配置中心",但它的功能远不止于此。
根据 Nacos 官方文档,其核心特性包括:
Nacos 的架构设计充分考虑了高可用、高并发和可扩展性,其核心架构如图所示:

Nacos 支持三种部署模式(官方文档:https://nacos.io/zh-cn/docs/deployment.html):

从 Nacos 官方 GitHub 仓库(https://github.com/alibaba/nacos/releases)下载最新稳定版本,本文使用当前最新版本 2.3.2。
# 下载压缩包
wget https://github.com/alibaba/nacos/releases/download/2.3.2/nacos-server-2.3.2.tar.gz
# 解压
tar -zxvf nacos-server-2.3.2.tar.gz -C /usr/local/
# 进入目录
cd /usr/local/nacos/bin
Nacos 默认使用嵌入式数据库,生产环境建议使用 MySQL。
CREATE DATABASE IF NOT EXISTS nacos_config CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 启用MySQL作为数据源
spring.datasource.platform=mysql
# 数据库数量
db.num=1
# 数据库连接信息
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root
# 单机模式启动
sh startup.sh -m standalone
# Windows系统
cmd startup.cmd -m standalone启动成功后,访问http://localhost:8848/nacos,默认用户名和密码都是 nacos。
对于生产环境,必须部署 Nacos 集群以保证高可用。以下是最小化集群部署方案(3 个节点)。
192.168.1.101:8848
192.168.1.102:8848
192.168.1.103:8848分别在每个节点执行启动命令:
sh startup.sh
使用 Nginx 作为前端负载均衡器,配置如下:
upstream nacos_cluster {
server 192.168.1.101:8848;
server 192.168.1.102:8848;
server 192.168.1.103:8848;
}
server {
listen 80;
server_name nacos.example.com;
location / {
proxy_pass http://nacos_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}通过http://nacos.example.com即可访问 Nacos 集群。
服务发现是微服务架构的核心能力,Nacos 提供了高效、可靠的服务注册与发现机制。
Nacos 的服务发现基于以下核心概念:
服务注册与发现流程:

创建 Spring Boot 项目,添加以下依赖(使用最新稳定版本):
<!-- Spring Cloud Alibaba Nacos Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2022.0.0.0-RC2</version>
</dependency>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- Commons Lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<!-- Spring Cloud LoadBalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>4.1.0</version>
</dependency>
在 application.yml 中添加配置:
spring:
application:
name: nacos-service-demo
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos服务器地址
namespace: public # 命名空间,默认为public
group: DEFAULT_GROUP # 服务分组,默认为DEFAULT_GROUP
cluster-name: DEFAULT # 集群名称,默认为DEFAULT
server:
port: 8080
在启动类上添加 @EnableDiscoveryClient 注解:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class NacosServiceApplication {
public static void main(String[] args) {
SpringApplication.run(NacosServiceApplication.class, args);
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户服务控制器
* 提供用户相关的服务接口
*/
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Value("${server.port}")
private int serverPort;
/**
* 根据用户ID获取用户信息
*
* @param userId 用户ID
* @return 用户信息
*/
@GetMapping("/{userId}")
public String getUserInfo(@PathVariable String userId) {
log.info("接收到获取用户信息的请求,用户ID:{}", userId);
// 实际应用中这里会调用服务获取真实用户信息
String result = String.format("用户ID: %s,服务端口: %d", userId, serverPort);
log.info("用户信息查询结果:{}", result);
return result;
}
}
使用 RestTemplate 调用服务:
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;
/**
* 配置类
* 定义应用所需的Bean
*/
@Configuration
public class RestTemplateConfig {
/**
* 创建负载均衡的RestTemplate实例
*
* @return RestTemplate对象
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* 订单服务控制器
* 作为服务消费者调用用户服务
*/
@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {
private static final String USER_SERVICE_URL = "http://nacos-service-demo/user/";
@Autowired
private RestTemplate restTemplate;
/**
* 根据用户ID创建订单
*
* @param userId 用户ID
* @return 订单创建结果
*/
@GetMapping("/create/{userId}")
public String createOrder(@PathVariable String userId) {
log.info("开始创建订单,用户ID:{}", userId);
// 参数校验
if (StringUtils.isBlank(userId)) {
log.error("创建订单失败,用户ID不能为空");
return "创建订单失败,用户ID不能为空";
}
// 调用用户服务获取用户信息
String userInfo = restTemplate.getForObject(USER_SERVICE_URL + userId, String.class);
if (StringUtils.isBlank(userInfo)) {
log.error("创建订单失败,获取用户信息为空,用户ID:{}", userId);
return "创建订单失败,用户不存在";
}
String result = String.format("订单创建成功,%s", userInfo);
log.info("订单创建结果:{}", result);
return result;
}
}
可以看到请求会交替分发到 8080 和 8081 两个服务实例,实现了负载均衡。
Nacos 提供了服务健康检查机制,确保服务消费者只调用健康的服务实例。
通过实现 HealthIndicator 接口自定义健康检查逻辑:
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
/**
* 自定义服务健康检查指示器
*/
@Component
public class CustomHealthIndicator implements HealthIndicator {
/**
* 检查服务健康状态
*
* @return 健康状态信息
*/
@Override
public Health health() {
// 实际应用中这里会包含真实的健康检查逻辑
boolean isHealthy = checkServiceHealth();
if (isHealthy) {
return Health.up()
.withDetail("status", "服务正常运行")
.withDetail("checkTime", System.currentTimeMillis())
.build();
} else {
return Health.down()
.withDetail("status", "服务异常")
.withDetail("error", "数据库连接失败")
.withDetail("checkTime", System.currentTimeMillis())
.build();
}
}
/**
* 模拟检查服务健康状态
*
* @return 健康状态:true-健康,false-不健康
*/
private boolean checkServiceHealth() {
// 实际应用中这里会检查数据库连接、缓存状态等
return true;
}
}添加 actuator 依赖以暴露健康检查端点:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>3.2.0</version>
</dependency>配置 actuator:
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
show-details: always
Nacos 允许为服务实例配置元数据和权重,实现更灵活的服务治理。
spring:
cloud:
nacos:
discovery:
metadata:
version: v1
environment: production
author: jam
可以通过 Nacos 控制台或 API 调整服务实例权重,权重越高的实例被调用的概率越大。
通过 API 设置权重:
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 服务管理控制器
* 提供服务权重调整等功能
*/
@RestController
@RequestMapping("/service")
@Slf4j
@RequiredArgsConstructor
public class ServiceManagementController {
private final NamingService namingService;
private final NacosDiscoveryProperties discoveryProperties;
/**
* 调整服务实例权重
*
* @param serviceName 服务名称
* @param ip 实例IP地址
* @param port 实例端口
* @param weight 权重值,范围0-100
* @return 操作结果
*/
@PostMapping("/weight")
public String updateWeight(
@RequestParam String serviceName,
@RequestParam String ip,
@RequestParam int port,
@RequestParam double weight) {
try {
// 验证权重值是否在有效范围内
if (weight < 0 || weight > 100) {
return "权重值必须在0-100之间";
}
Instance instance = new Instance();
instance.setIp(ip);
instance.setPort(port);
instance.setWeight(weight);
// 更新实例权重
namingService.modifyInstance(serviceName, discoveryProperties.getGroup(), instance);
log.info("服务实例权重更新成功,服务名:{},IP:{},端口:{},新权重:{}",
serviceName, ip, port, weight);
return "权重更新成功";
} catch (NacosException e) {
log.error("更新服务实例权重失败", e);
return "权重更新失败:" + e.getMessage();
}
}
}
Nacos 配置中心提供了集中式的配置管理能力,支持动态配置更新,无需重启服务。
配置的组织结构:Namespace + Group + Data ID唯一确定一个配置。
<!-- Spring Cloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2022.0.0.0-RC2</version>
</dependency>
创建 bootstrap.yml 配置文件(bootstrap 配置优先于 application 配置加载):
spring:
application:
name: nacos-config-demo
cloud:
nacos:
config:
server-addr: localhost:8848 # Nacos服务器地址
file-extension: yaml # 配置文件格式
namespace: public # 命名空间
group: DEFAULT_GROUP # 配置分组
# 配置刷新策略
refresh-enabled: true
# 配置重试策略
retry:
max-retry: 3
initial-interval: 1000
max-interval: 2000
multiplier: 1.1
访问 Nacos 控制台,进入 "配置管理" -> "配置列表"
点击 "新增" 按钮,创建配置:
使用 @Value 注解或 @ConfigurationProperties 注解读取配置。
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 应用配置属性
* 映射Nacos中的配置
*/
@Component
@ConfigurationProperties(prefix = "app")
@Data
public class AppConfigProperties {
private String version;
private boolean enabled;
private String description;
}import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 配置测试控制器
* 演示如何读取Nacos配置中心的配置
*/
@RestController
@RequestMapping("/config")
@Slf4j
@RefreshScope // 支持配置动态刷新
public class ConfigTestController {
@Value("${user.name:}")
private String userName;
@Value("${user.age:0}")
private int userAge;
@Resource
private AppConfigProperties appConfigProperties;
/**
* 获取用户配置信息
*
* @return 用户配置信息
*/
@GetMapping("/user")
public String getUserConfig() {
log.info("获取用户配置信息,姓名:{},年龄:{}", userName, userAge);
if (StringUtils.isBlank(userName)) {
return "未配置用户信息";
}
return String.format("用户姓名:%s,年龄:%d", userName, userAge);
}
/**
* 获取应用配置信息
*
* @return 应用配置信息
*/
@GetMapping("/app")
public String getAppConfig() {
log.info("获取应用配置信息,版本:{},状态:{}",
appConfigProperties.getVersion(),
appConfigProperties.isEnabled() ? "启用" : "禁用");
return String.format("应用版本:%s,状态:%s,描述:%s",
appConfigProperties.getVersion(),
appConfigProperties.isEnabled() ? "启用" : "禁用",
appConfigProperties.getDescription());
}
}
@RefreshScope 注解用于实现配置的动态刷新,当 Nacos 中的配置发生变化时,无需重启服务即可生效。
Nacos 配置中心的动态刷新基于以下机制:

在实际开发中,我们需要为不同环境(开发、测试、生产)维护不同的配置。Nacos 提供了多种实现多环境配置的方式。
spring:
cloud:
nacos:
config:
namespace: dev # 开发环境
# namespace: test # 测试环境
# namespace: prod # 生产环境
spring:
cloud:
nacos:
config:
group: DEV_GROUP # 开发环境
# group: TEST_GROUP # 测试环境
# group: PROD_GROUP # 生产环境
对于多个应用共享的配置,可以使用 shared-configs 或 extension-configs:
spring:
cloud:
nacos:
config:
shared-configs:
- data-id: common.yaml
group: COMMON_GROUP
refresh: true
- data-id: db.yaml
group: COMMON_GROUP
refresh: true
extension-configs:
- data-id: redis.yaml
group: CACHE_GROUP
refresh: true生产环境中的配置往往包含敏感信息(如数据库密码、API 密钥等),需要进行加密存储。
Nacos 支持对配置进行加密,结合 Spring Cloud Alibaba 的加密功能:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-encryption-core</artifactId>
<version>2022.0.0.0-RC2</version>
</dependency>encrypt:
key: your-encryption-key # 实际应用中应使用更复杂的密钥
可以通过 Spring Boot 提供的加密端点或代码生成加密后的字符串:
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.keygen.KeyGenerators;
public class EncryptionDemo {
public static void main(String[] args) {
String salt = KeyGenerators.string().generateKey();
String password = "db-password-123";
String encryptPassword = Encryptors.text("your-encryption-key", salt).encrypt(password);
System.out.println("加密后的密码:" + encryptPassword);
System.out.println("盐值:" + salt);
}
}db:
password: "{cipher}加密后的密码"
Nacos 提供了完善的权限控制机制,通过控制台的 "权限控制" 模块可以管理用户、角色和权限。
nacos.core.auth.enabled=true
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
Nacos 结合 Spring Cloud LoadBalancer 可以实现复杂的服务路由策略。
Nacos 默认支持基于权重的负载均衡,权重越高的服务实例被调用的概率越大。
通过实现自定义负载均衡器,可以基于服务实例的元数据进行路由:
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
/**
* 基于版本的负载均衡器
* 根据请求中的版本信息路由到相应版本的服务实例
*/
public class VersionBasedLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private final String serviceId;
private final ServiceInstanceListSupplier serviceInstanceListSupplier;
private final Random random = new Random();
public VersionBasedLoadBalancer(String serviceId, ServiceInstanceListSupplier serviceInstanceListSupplier) {
this.serviceId = serviceId;
this.serviceInstanceListSupplier = serviceInstanceListSupplier;
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
return serviceInstanceListSupplier.get(request)
.next()
.map(serviceInstances -> selectInstance(serviceInstances, request));
}
/**
* 选择合适的服务实例
*
* @param serviceInstances 服务实例列表
* @param request 请求对象
* @return 选中的服务实例
*/
private Response<ServiceInstance> selectInstance(List<ServiceInstance> serviceInstances, Request request) {
if (serviceInstances.isEmpty()) {
return new EmptyResponse();
}
// 从请求中获取目标版本(实际应用中需要根据具体情况实现)
String targetVersion = getTargetVersionFromRequest(request);
// 过滤出匹配版本的服务实例
List<ServiceInstance> matchedInstances = serviceInstances.stream()
.filter(instance -> targetVersion.equals(instance.getMetadata().get("version")))
.collect(Collectors.toList());
// 如果没有匹配的实例,使用所有实例
if (matchedInstances.isEmpty()) {
matchedInstances = serviceInstances;
}
// 随机选择一个实例
int index = random.nextInt(matchedInstances.size());
ServiceInstance selectedInstance = matchedInstances.get(index);
return new DefaultResponse(selectedInstance);
}
/**
* 从请求中获取目标版本
*
* @param request 请求对象
* @return 目标版本
*/
private String getTargetVersionFromRequest(Request request) {
// 实际应用中需要根据请求参数或Header获取目标版本
// 这里简化处理,默认返回v1
return "v1";
}
}
配置自定义负载均衡器:
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* 负载均衡配置
*/
@Configuration
public class LoadBalancerConfig {
/**
* 创建基于版本的负载均衡器
*
* @param environment 环境对象
* @param loadBalancerClientFactory 负载均衡客户端工厂
* @return 基于版本的负载均衡器
*/
@Bean
public VersionBasedLoadBalancer versionBasedLoadBalancer(
Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String serviceId = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
ServiceInstanceListSupplier supplier = loadBalancerClientFactory
.getLazyProvider(serviceId, ServiceInstanceListSupplier.class);
return new VersionBasedLoadBalancer(serviceId, supplier);
}
}
除了使用 @RefreshScope,还可以通过编程方式监听配置变化:
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.Executor;
/**
* Nacos配置监听器
* 监听特定配置的变化并处理
*/
@Component
@Slf4j
public class NacosConfigListener {
@Resource
private NacosConfigManager nacosConfigManager;
/**
* 初始化配置监听器
*/
@PostConstruct
public void init() {
try {
// 监听user-config.yaml配置的变化
nacosConfigManager.getConfigService().addListener(
"user-config.yaml",
"DEFAULT_GROUP",
new Listener() {
@Override
public Executor getExecutor() {
return null; // 使用默认线程池
}
@Override
public void receiveConfigInfo(String configInfo) {
if (StringUtils.isBlank(configInfo)) {
log.warn("接收到空的配置信息");
return;
}
log.info("用户配置发生变化,新配置内容:\n{}", configInfo);
// 处理配置变更
handleUserConfigChange(configInfo);
}
}
);
log.info("Nacos配置监听器初始化成功");
} catch (NacosException e) {
log.error("初始化Nacos配置监听器失败", e);
}
}
/**
* 处理用户配置变更
*
* @param newConfig 新的配置内容
*/
private void handleUserConfigChange(String newConfig) {
// 实际应用中这里会解析新配置并更新相关业务逻辑
// 例如:更新缓存、重新初始化组件等
}
}
Nacos 提供了配置的导出和导入功能,方便配置的迁移和备份。
通过 API 导出配置:
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* 配置导出服务
* 用于导出Nacos中的配置
*/
@Service
@Slf4j
public class ConfigExportService {
@Resource
private NacosConfigManager nacosConfigManager;
/**
* 导出指定Data ID的配置
*
* @param dataId 配置ID
* @param group 配置分组
* @param namespace 命名空间
* @param filePath 导出文件路径
* @return 导出是否成功
*/
public boolean exportConfig(String dataId, String group, String namespace, String filePath) {
try {
// 参数校验
if (StringUtils.isBlank(dataId) || StringUtils.isBlank(filePath)) {
log.error("导出配置失败,dataId和文件路径不能为空");
return false;
}
// 获取配置内容
String configContent = nacosConfigManager.getConfigService()
.getConfig(dataId, group, 5000);
if (StringUtils.isBlank(configContent)) {
log.warn("配置内容为空,dataId:{},group:{}", dataId, group);
return false;
}
// 写入文件
File file = new File(filePath);
// 创建父目录
if (!file.getParentFile().exists()) {
boolean mkdirs = file.getParentFile().mkdirs();
if (!mkdirs) {
log.error("创建目录失败,路径:{}", file.getParentFile().getAbsolutePath());
return false;
}
}
try (FileWriter writer = new FileWriter(file)) {
writer.write(configContent);
}
log.info("配置导出成功,dataId:{},文件路径:{}", dataId, filePath);
return true;
} catch (NacosException | IOException e) {
log.error("导出配置失败", e);
return false;
}
}
}
Nacos 可以与分布式事务解决方案(如 Seata)结合使用,提供服务注册与配置管理能力。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2022.0.0.0-RC2</version>
</dependency>seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: my_test_tx_group
registry:
type: nacos
nacos:
server-addr: localhost:8848
namespace: public
group: SEATA_GROUP
application: seata-server
config:
type: nacos
nacos:
server-addr: localhost:8848
namespace: public
group: SEATA_GROUP
合理的命名空间和配置分组设计可以提高配置管理效率:

大型应用可以将配置分为多个层级,实现配置的继承和覆盖:
配置加载顺序:基础配置 < 中间件配置 < 应用配置 < 环境配置(后面的配置会覆盖前面的)
spring:
cloud:
nacos:
discovery:
# 健康检查间隔,单位:毫秒
heart-beat-interval: 5000
# 健康检查超时时间,单位:毫秒
heart-beat-timeout: 15000
# 实例不健康的阈值
ip-delete-timeout: 30000
JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"Nacos 源码主要包含以下核心模块:
服务注册的核心代码在 nacos-naming 模块中:
// 服务注册核心逻辑
public class ServiceRegistryImpl implements ServiceRegistry {
private final NamingProxy serverProxy;
@Override
public void registerInstance(String serviceName, String groupName, Instance instance) {
// 参数校验
Objects.requireNonNull(serviceName, "服务名称不能为空");
Objects.requireNonNull(instance, "服务实例不能为空");
try {
// 构建注册请求
RegisterInstanceRequest request = new RegisterInstanceRequest();
request.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
request.setInstance(instance);
// 发送注册请求到Nacos服务器
serverProxy.registerService(request);
log.info("服务实例注册成功,服务名:{},实例:{}", serviceName, instance);
} catch (Exception e) {
log.error("服务实例注册失败,服务名:{},实例:{}", serviceName, instance, e);
throw new NacosException(NacosException.SERVER_ERROR, "服务注册失败", e);
}
}
}
配置中心的核心逻辑在 nacos-config 模块中,配置获取流程:
// 配置获取核心逻辑
public class ConfigServiceHttpClientImpl implements ConfigService {
private final HttpAgent httpAgent;
@Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
// 参数校验
StringUtils.hasText(dataId, "dataId不能为空");
StringUtils.hasText(group, "group不能为空");
// 构建配置ID
String configId = NacosConfigUtils.getConfigId(dataId, group);
// 先从本地缓存获取
String content = LocalConfigInfoProcessor.getFailover(configId);
if (StringUtils.isNotEmpty(content)) {
log.info("从本地故障转移缓存获取配置,dataId:{},group:{}", dataId, group);
return content;
}
// 从服务器获取配置
content = getConfigFromServer(dataId, group, timeoutMs);
// 更新本地缓存
LocalConfigInfoProcessor.saveSnapshot(configId, content);
return content;
}
private String getConfigFromServer(String dataId, String group, long timeoutMs) throws NacosException {
// 构建请求参数
Map<String, String> params = new HashMap<>(4);
params.put("dataId", dataId);
params.put("group", group);
// 发送HTTP请求获取配置
HttpResult result = httpAgent.httpGet("/nacos/v1/cs/configs", null, params, timeoutMs);
// 处理响应
if (result.ok()) {
return result.getData();
} else if (result.getCode() == HttpURLConnection.HTTP_NOT_FOUND) {
return null;
} else {
throw new NacosException(result.getCode(), "获取配置失败:" + result.getData());
}
}
}
Nacos 提供了丰富的扩展点,可以通过 SPI 机制进行扩展。
例如,自定义配置加密器:
import com.alibaba.nacos.api.config.filter.Converter;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* 自定义AES配置加密器
*/
public class AesConfigConverter implements Converter {
private static final String ALGORITHM = "AES";
private static final String DEFAULT_KEY = "nacos1234567890"; // 实际应用中应从安全渠道获取密钥
@Override
public String convert(String source) {
try {
// 解密逻辑
SecretKey secretKey = new SecretKeySpec(DEFAULT_KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decoded = Base64.decodeBase64(source);
return new String(cipher.doFinal(decoded));
} catch (Exception e) {
throw new RuntimeException("配置解密失败", e);
}
}
@Override
public String revert(String target) {
try {
// 加密逻辑
SecretKey secretKey = new SecretKeySpec(DEFAULT_KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(target.getBytes());
return Base64.encodeBase64String(encrypted);
} catch (Exception e) {
throw new RuntimeException("配置加密失败", e);
}
}
}com.example.config.AesConfigConverterspring:
cloud:
nacos:
config:
converter: com.example.config.AesConfigConverter
Nacos 作为服务发现和配置中心,具有以下优势:
Nacos 适用于各种规模的微服务架构,特别适合: