前言
该博客为Nacos
学习笔记,主要目的是为了帮助后期快速复习使用
学习视频:7小快速通关SpringCloud
辅助文档:SpringCloud快速通关
源码地址:cloud-demo
一、简介
Nacos官网:https://nacos.io/docs/next/quickstart/quick-start/
Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现
、配置管理
和服务管理
平台。
二、安装
2.1 Windows本地安装:
- 点击下载
- 找到对应版本的二进制下载
- 将压缩包解压到非中文无空格的目录
- 找到并进入
bin
目录,在地址栏输入cmd,打开黑窗口 - 输入
startup.cmd -m standalone
启动,看到logo即启动成功【注意:黑窗口不能关闭】 - 在浏览器输入
http://localhost:8848/nacos/
2.2 Docker安装【推荐】
docker run -d -p 8848:8848 -p 9848:9848 -e MODE=standalone --name nacos nacos/nacos-server:v2.4.3
三、注册中心
3.1 整合配置
3.1.1 依赖引入
<!-- web场景 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!-- 服务发现Nacos -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
3.1.2 编写yml配置文件
# 服务端口
server:port: 8000spring:application:name: service-order # 服务名称cloud:nacos:server-addr: 127.0.0.1:8848 # nacos地址(默认)
3.1.3 编写主程序
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args) {SpringApplication.run(OrderMainApplication.class, args);}
}
3.1.4 运行主程序,查看注册中心效果
运行成功,可以在服务列表中查看到
3.2 单机模拟集群启动
- 点击
服务
- 找到
OrderMainApplication
,右键,点击复制配置
- 点击
修改选项
,将程序参数
勾选上
- 重新指定运行端口
--
+ 配置,修改完成点击确定
--server.port=8001
- 右键
运行
,查看Nacos服务列表
3.3 服务发现
3.3.1 开启服务发现功能
在主程序上加上@EnableDiscoveryClient
, 启用服务注册发现功能
3.3.2编写测试用例
3.3.2.1 依赖引入
<!-- 测试场景 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
3.3.2.2 使用DiscoveryClient测试服务发现API
@SpringBootTest
public class DiscoveryTest {@Autowiredprivate DiscoveryClient discoveryClient; // 服务发现客户端@Testvoid discoveryClientTest() {for (String service : discoveryClient.getServices()) {System.out.println("service = " + service);// 获取服务实例 ip + portList<ServiceInstance> instances = discoveryClient.getInstances(service);for (ServiceInstance instance : instances) {System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());}}}
}
3.3.2.3 使用NacosServiceDiscovery测试服务发现API
@SpringBootTest
public class DiscoveryTest {@Autowiredprivate NacosServiceDiscovery nacosServiceDiscovery; // nacos服务发现客户端@Testvoid nacosServiceDiscoveryTest() throws NacosException {for (String service : nacosServiceDiscovery.getServices()) {System.out.println("service = " + service);List<ServiceInstance> instances = nacosServiceDiscovery.getInstances(service);for (ServiceInstance instance : instances) {System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());}}}
}
DiscoveryClient
和NacosServiceDiscovery
区别:
- 抽象层次:
- DiscoveryClient 是一个通用接口,位于抽象层,不依赖于具体的服务注册中心。
- NacosServiceDiscovery 是 DiscoveryClient 的具体实现,依赖于 Nacos。
- 功能实现:
- DiscoveryClient 定义了服务发现的基本行为,但具体实现由各个服务注册中心提供。
- NacosServiceDiscovery 提供了对 Nacos 的具体实现,包括与 Nacos 服务器的通信逻辑。
- 使用方式:
- 在 Spring Cloud 应用程序中,通常通过
@EnableDiscoveryClient
注解启用服务发现功能,底层会自动选择合适的 DiscoveryClient 实现。- 如果使用 Nacos 作为服务注册中心,NacosServiceDiscovery 会被自动配置为 DiscoveryClient 的实现。
3.4 远程调用
3.4.1 服务之间调用的基本流程
以订单服务调用商品服务为例:
- 订单服务向注册中心获取商品服务可访问地址列表
- 注册中返回商品服务地址列表
- 订单服务从地址列表中选择一个地址
- 订单服务向选中的商品服务地址发送请求
- 商品服务处理请求并返回数据
- 订单服务接收商品服务返回的数据
在上一篇博客中详细讲解:RestTemplate快速入门
3.5 负载均衡
3.5.1 依赖引入
<!--loadbalancer-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
3.5.2 使用LoadBalancerClient开启负载均衡
3.5.2.1 测试
@SpringBootTest
public class LoadBalancerTest {@AutowiredLoadBalancerClient loadBalancerClient;@Testpublic void test() {ServiceInstance choose = loadBalancerClient.choose("service-product");System.out.println(choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println(choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println(choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println(choose.getHost() + ":" + choose.getPort());}
}
3.5.2.2 使用示例
定义远程调用客户端RestTemplate
Bean对象
@Configuration
public class OrderConfig {@Bean@LoadBalanced //注解式负载均衡public RestTemplate restTemplate() {return new RestTemplate();}
}
假设有一个服务名为service-product
,通过RestTemplate调用其/product
接口的代码如下
// 注入LoadBalancerClient对象
@Autowired
private LoadBalancerClient loadBalancerClient;// 负载均衡发送请求
private Product getProductFromRemoteWithLoadBalancer(Long productId) {// 1. 获取到商品服务所在的所有机器IP + portServiceInstance choose = loadBalancerClient.choose("service-product");// 2. 根据IP + port调用商品服务String url = "http://" + choose.getHost() + ":" + choose.getPort() + "/product/" + productId;log.info("调用商品服务: {}", url);// 调用商品服务return restTemplate.getForObject(url, Product.class);}
3.5.3 使用@LoadBalanced注解开启负载均衡
3.5.3.1 使用示例
在远程调用客户端RestTemplate的Bean对象上,加上@LoadBalanced
注解,开启负载均衡
@Configuration
public class OrderConfig {@Bean@LoadBalanced //注解式负载均衡public RestTemplate restTemplate() {return new RestTemplate();}
}
假设有一个服务名为service-product
,通过RestTemplate调用其/product
接口的代码如下
// 基于注解的负载均衡发送请求
private Product getProductFromRemoteWithLoadBalancerAnnotation(Long productId) {String url = "http://service-product/product/" + productId;// 调用商品服务,service-product为服务名称, 会被动态替换return restTemplate.getForObject(url, Product.class);}
3.5.3.2 调用过程解析
当RestTemplate通过@LoadBalanced
注解被标记为负载均衡客户端时,它会与服务发现机制集成。在调用http://service-product/product/
时,
- RestTemplate会首先向服务注册中心查询
service-product
服务的所有可用实例。 - 服务注册中心会返回一个实例列表
- RestTemplate会根据配置的负载均衡策略(如轮询、随机等)从这些实例中选择一个进行调用
3.5.3.3 深入探索
经典面试题:如果注册中心宕机,远程调用是否可以成功?
- 从未调用过,如果宕机,调用会立即失败
- 调用过,如果宕机,因为会缓存名单,调用会成功
- 调用过,如果注册中心和对方服务宕机,因为会缓存名单,调用会阻塞后失败(Connection Refused)
四、配置中心
4.1 整合配置
4.1.1 依赖引入
<!-- 配置中心 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
4.1.2 编写yml配置文件
spring:cloud:nacos:server-addr: 127.0.0.1:8848 # nacos地址(默认)config:import: nacos:service-order.properties
4.1.3 配置集-dataId
在浏览器中的Nacos可视化平台,找到配置管理,点击配置列表,新建一个配置
注意:
Data ID 要和 yml配置文件 中的完全一致
注意:
当我们在项目引入了Nacos的配置中心的依赖,在项目启动前没导入任何的配置,就会报如下错误:
17:28:47.552 [main] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter -- ***************************
APPLICATION FAILED TO START
***************************Description:No spring.config.import property has been definedAction:Add a spring.config.import=nacos: property to your configuration.If configuration is not required add spring.config.import=optional:nacos: instead.To disable this check, set spring.cloud.nacos.config.import-check.enabled=false.
解决方法
- 添加可选配置
# properties文件
spring.config.import=optional:nacos: # 可选
- 在yml配置中禁用导入检查
spring:cloud:nacos:config:import-check:enabled: false # 禁用配置检查
4.2 动态刷新
4.2.1 @RefreshScope
@RefreshScope
->
激活配置中心的自动刷新功能
@RestController
@RequiredArgsConstructor
@RefreshScope//自动刷新
public class OrderController {private final OrderService orderService;@Value("${order.timeout}")String orderTimeout;@Value("${order.timeout}")String orderAutoConfirm;@GetMapping("/config")public String getConfig() {return "timeout:" + orderTimeout + ",autoConfirm:" + orderAutoConfirm;}
}
启动项目,可见如下日志
2025-02-07T17:11:12.391+08:00 INFO 8056 --- [service-order] [ main] c.a.c.n.c.NacosConfigDataLoader : [Nacos Config] Load config[dataId=service-order.properties, group=DEFAULT_GROUP] success
2025-02-07T17:11:13.761+08:00 INFO 8056 --- [service-order] [ main] c.a.c.n.refresh.NacosContextRefresher : [Nacos Config] Listening config: dataId=service-order.properties, group=DEFAULT_GROUP
在浏览器输入http://localhost:8000/config
,即可得到配置内容,在配置中心修改也可同步修改
4.2.2 @ConfigurationProperties
在配置文件中的属性较多的时候,使用@Value
注解就显得有点繁琐。可以使用 @ConfigurationProperties
进行批量属性绑定,并且无需 @RefreshScope
,自动绑定配置,动态更新
抽取配置类,参考代码如下:
@Component
@ConfigurationProperties(prefix = "order") //配置批量绑定在nacos下,可以无需@RefreshScope就能实现自动刷新
@Data
public class OrderProperties {String timeout;String autoConfirm;String dbUrl;
}
@RestController
@RequiredArgsConstructor
public class OrderController {private final OrderProperties orderProperties; //注入订单配置类@GetMapping("/config")public String getConfig() {return "timeout:" + orderProperties.getTimeout() + ",autoConfirm:" + orderProperties.getAutoConfirm();}}
4.3 手动编写代码监听配置变化
/*** 创建并配置ApplicationRunner bean* 该bean在应用启动后,执行指定的操作,这里用于监听Nacos配置变化** @param manager NacosConfigManager实例,用于与Nacos配置服务交互* @return ApplicationRunner实例,用于执行应用启动后的操作*/@BeanApplicationRunner applicationRunner(NacosConfigManager manager){return args -> {// 获取Nacos配置服务实例ConfigService configService = manager.getConfigService();// 为特定的配置文件添加监听器// 这里监听"service-order.properties"配置文件的变化configService.addListener("service-order.properties", "DEFAULT_GROUP", new Listener() {/*** 返回一个固定大小的线程池,用于异步处理配置变更** @return Executor实例,用于异步执行任务*/@Overridepublic Executor getExecutor() {// 创建一个包含4个线程的固定大小线程池return Executors.newFixedThreadPool(4);}/*** 当监听的配置信息发生变化时,该方法被调用** @param configInfo 变更后的配置信息*/@Overridepublic void receiveConfigInfo(String configInfo) {// 打印变更后的配置信息System.out.println("configInfo = " + configInfo);}});};}
思考:Nacos
中的数据集 和 application.properties
有相同的 配置项,哪个生效?
参考答案:Nacos
中的数据集的优先级高于本地application.properties
,因此Nacos
中的数据集的会生效。遵循先导入优先,外部优先
,高优先级的配置会覆盖低优先级相同的配置。
4.4 数据隔离
4.4.1 namespace
**命名空间:**实现多环境隔离,如:开发、测试、预发、生产等
创建方式如下图:
4.4.2 dataId
**数据集id:**就是以前配置文件的名字。完整写法:名字.后缀 如:common.properties
4.4.3 groupId
**分组id:**一般可以用微服务的名字作为自己的组。
创建方式如下图:
点击创建配置后,填写配置信息
4.4.4 推荐用法
namespace
【命名空间】、dataId
【数据集】、group
【组】配合 spring.config.activate.on-profile
实现配置环境隔离
“通俗易懂”:多个命名空间,每个命名空间下有多个组,每个组就是一个微服务,每个微服务下又有多个配置文件即数据集,每个配置文件下又有多个配置项
4.4.4 按需加载
# 服务端口
server:port: 8000spring:profiles:active: dev # 指定环境application:name: service-order # 服务名称cloud:nacos:server-addr: 127.0.0.1:8848 # nacos地址(默认)config:import-check:enabled: false # 禁用配置检查 -> 记得开启不然会报错namespace: ${spring.profiles.active:public} # 指定命名空间 -> 采用 spring.profiles.active的值,默认为public---
spring:config:import:- nacos:common.properties?group=order # 配置文件地址 group->指定组名- nacos:database.properties?group=orderactivate:on-profile: dev # 指定dev环境启用---
spring:config:import:- nacos:common.properties?group=order # 配置文件地址 group->指定组名- nacos:database.properties?group=order- nacos:haha.properties?group=orderactivate:on-profile: test # 指定test环境启用---
spring:config:import:- nacos:common.properties?group=order # 配置文件地址 group->指定组名- nacos:database.properties?group=order- nacos:hehe.properties?group=orderactivate:on-profile: prod # 指定prod环境启用