Nacos—注册中心&配置中心
Nacos官网| Nacos 配置中心 | Nacos 下载| Nacos 官方社区
什么是注册中心Nacos
Nacos两大核心功能:服务注册与服务发现

安装Nacos
https://nacos.io/download/release-history/?spm=5238cd80.2ef5001f.0.0.3f613b7c4NDiBh
直接下载zip压缩包,解压后运行即可
1
|
startup.cmd -m standalone
|

访问:http://127.0.0.1:8848/nacos

Nacos服务注册功能

启动微服务
在service-order微服务模块中写一个SpringBoot的启动类

创建配置文件application.properties
1
2
3
|
spring.application.name=service-order //服务名称
sercer.port=8000 //服务启动端口
spring.cloud.nacos.server-addr=127.0.0.1:8848 //nacos地址
|
此时访问本地nacos服务器,发现nacos中存在service-order即注册成功

集群模式启动测试
控制台右键复制配置

编辑配置,将端口改一下运行即可,如下图所示
此时nacos注册中心实例数就有3个了

Nacos服务发现

开启服务发现功能
在SpringBoot的启动类中添加注解@EnableDiscoveryClient
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient //开启服务注册与发现功能
@SpringBootApplication
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
}
|
测试服务发现API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@SpringBootTest
public class productTest {
@Autowired
DiscoveryClient discoveryClient;
@Test
public void discoveryClient() {
// 服务注册与发现功能的测试代码
discoveryClient.getServices().forEach(service ->
System.out.println("service"+service)
);
//获取服务的IP和端口信息
discoveryClient.getInstances("product-service").forEach(instance ->
System.out.println("instance"+instance.getHost()+"\n"+instance.getPort()+"\n"+instance.getUri())
);
}
}
|

使用nacosServiceDiscovery进行服务发现测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Autowired
NacosServiceDiscovery nacosServiceDiscovery; //获取服务信息
@Test
void nacosServiceDiscovery() throws NacosException {
// 服务注册与发现功能的测试代码
nacosServiceDiscovery.getServices().forEach(service ->
System.out.println("service"+service)
);
//获取服务的IP和端口信息
nacosServiceDiscovery.getInstances("product-service").forEach(instance ->
System.out.println("instance"+instance.getHost()+"\n"+instance.getPort())
);
}
|

4.远程调用—下单场景
远程调用基本流程

首先要定义两个微服务模块,分别是order模块和product模块,分别在这两个模块中编写对应的逻辑代码,这两个模块不需要写实体类pojo,将所有微服务的实体类抽取出来放到model模块统一管理
order和product模块要使用实体类直接在pom文件中加载依赖即可,如果不这样做的话如果订单模块要使用product模块就会很麻烦

负载均衡API测试
根据配置的策略从可用实例中选择一个,默认使用轮询算法,这次调用9001,下次调用9002,在又是9001
1
2
3
4
5
|
//在order的pom文件中引入对应依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@SpringBootTest
public class LoadBalancerTest {
LoadBalancerClient loadBalancerClient;
@Test
public void test(){
ServiceInstance choose = loadBalancerClient.choose("product-service");
System.out.println(choose.getHost()+":"+choose.getPort());
ServiceInstance choose1 = loadBalancerClient.choose("product-service");
System.out.println(choose1.getHost()+":"+choose1.getPort());
ServiceInstance choose2 = loadBalancerClient.choose("product-service");
System.out.println(choose2.getHost()+":"+choose2.getPort());
}
}
|

使用@LoadBanlancer注解完成负载均衡调用
1
2
3
4
5
6
|
//将注解放到远程调用客户端上即可
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
|
1
2
3
4
5
6
7
8
9
10
|
private product getProductFromRemote2(Long productId) {
// 1. 获取商品服务所在的 IP 地址
// 2. 构造请求 URL,product-service微服务的IP地址
String url = "http://product-service/product/" + productId;
// 3. 发送请求,获取商品信息
log.info("请求URL: {}", url);
product product = restTemplate.getForObject(url, product.class);
return product;
}
|
**面试题:**注册中心Nacos如果宕机,那么还能成功完成远程调用吗?
1.注册中心如果宕机,以前调用过那么可以从示例缓存中获取IP地址,还能成功完成远程调用
2.注册中心宕机,如果以前没调用过,那么第一次需要在注册中心获取地址,不能完成远程调用
Nacos配置中心

动态刷新
1
|
@Value("${xxx}")获取配置+@RefreshScope实现自动刷新
|
项目中使用方法:
1.启动Nacos
2.导入Nacos作为配置中心的依赖
1
2
3
4
|
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
|
3.在配置文件properties编写配置
1
2
3
4
|
spring.application.name=service-order
sercer.port=8000
spring.cloud.nacos.server-addr=127.0.0.1:8848
spring.config.import=nacos:service-order.properties //指定导入的配置文件
|
4.在创建data-id数据集

要使用这些配置文件,可以使用Value注解加载
1
2
3
4
5
6
7
8
9
10
11
|
@Value("${order.timeout}")
String orderTimeouut;
@Value("${order.auto-confirm}")
String orderConfirm;
@GetMapping("/config")
String config(){
System.out.println("orderTimeouut:"+orderTimeouut);
System.out.println("orderConfirm:"+orderConfirm);
return orderTimeouut+" "+orderConfirm;
}
|

此时如果直接修改Nacos配置文件的值,这个配置文件是不会自动刷新的,如果想要开启自动刷新的话,需要使用注解在类上添加
1
|
@RefreshScope //开启配置文件自动刷新注解
|
一旦项目导入了Nacos的配置中心,那么项目启动前配置文件必须导入Nacos的配置,如果没有导入那么项目会启动报错
1
2
3
4
|
两种解决方法
1.禁用Nacos的导入检查
spring.cloud.nacos.config.import-check.enabled=false
2.设置Nacos的导入为可选的,不是必须的
|
无感知自动刷新
创建一个properties配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.example.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "order")
public class OrderProperties {
String timeouut;
String autoconfirm;
}
|

想要使用配置文件直接依赖注入即可
1
2
3
4
5
6
7
8
9
10
|
@Autowired
OrderProperties orderProperties;
@GetMapping("/config")
String config(){
System.out.println("orderTimeouut:"+orderProperties.getTimeout());
System.out.println("orderConfirm:"+orderProperties.getAutoconfirm());
return orderProperties.getTimeout()+" "+orderProperties.getAutoconfirm();
}
|
配置监听
先说一个场景:当Nacos的配置文件发生变更时发送邮件给开发者
- 项目启动时监听Nacos配置文件变化
1. 获取最新的配置数据
2. 发送邮件通知开发者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package com.example;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.client.config.NacosConfigService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import java.util.concurrent.Executor;
@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
/**
* 项目启动时监听Nacos配置文件变化
* 1. 获取最新的配置数据
* 2. 发送邮件通知开发者
*/
@Bean
public ApplicationRunner runner(NacosConfigManager nacosConfigManager) {
return args -> {
NacosConfigService nacosConfigService = (NacosConfigService) nacosConfigManager.getConfigService();
nacosConfigService.addListener(
"com.example.OrderProperties",
"defaultGroup",
new Listener() {
@Override
public Executor getExecutor() {
return Runnable::run; // 修正:原代码中的Executor.newFixedThreadPool(4)不正确
}
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("配置文件更新了,最新的配置信息为:" + configInfo);
// 发送邮件通知开发者
// 此处省略发送邮件的代码
System.out.println("邮件已发送");
}
}
);
};
}
}
|
思考:如果Nacos的配置文件数据集和项目中的配置文件有相同项,哪个会生效?
先导入优先,外部优先,所以Nacos的配置文件会优先生效
1
2
3
4
5
6
|
spring.application.name=service-order
sercer.port=8000
spring.cloud.nacos.server-addr=127.0.0.1:8848
spring.config.import=nacos:service-order.properties,nacos:common.properties
//service-order.properties优先级最高common.properties第二高
spring.cloud.nacos.config.import-check.enabled=false
|

数据隔离
先说场景:假设现在有这么一个需求:项目有多套环境:开发,测试,生产环境,而每一个环境在每套环境下配置文件都不一样
难点:区分多套环境,区分多种配置,区分多种微服务该怎么解决

解决方法:
使用Namespace名称空间区分多套环境,使用Group分组区分多种微服务,使用Data-id数据集区分多种配置

如何实现呢???
1.在Nacos的命名空间中新建名称空间

2.创建好开发测试生产环境的命名空间后,在配置管理者找到对应空间,新增配置

3.动态切换环境
在微服务的配置文件中定义命名空间和组名,但是这样子不能实现动态切换环境
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
sercer:
port: 8000
spring:
application:
name: service-order
cloud:
nacos:
server-addr: 127.0.0.1:8848
import-check:
enabled=false:
config:
namespace: dev
config:
import:
- nacos:Common.properties?group=order
- nacos:database.properties?group=order
|
完整的配置文件如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
sercer:
port: 8000
spring:
profiles:
active: dev //选择dev环境的配置文件
//active:test //选择test环境下的配置文件
application:
name: service-order
cloud:
nacos:
server-addr: 127.0.0.1:8848
import-check:
enabled=false:
config:
namespace: ${spring.profiles.active:public}
--- //三个杠表示多文档模式
spring:
config:
import:
- nacos:Common.properties?group=order
- nacos:database.properties?group=order
activate:
on-profile: dev
---
spring:
config:
import:
- nacos:Common.properties?group=order
- nacos:database.properties?group=order
- nacos:redis.properties?group=order
activate:
on-profile: test
---
spring:
config:
import:
- nacos:Common.properties?group=order
- nacos:database.properties?group=order
- nacos:haha.properties?group=order
activate:
on-profile: prod
|
