Nacos配置中心
当我们把一个单体应用拆分成多个应用时,就会从一个配置文件 拆分成多个配置文件,管理这么多的配置文件,十分复杂和繁琐。
为了优化这个问题,我们可以把多个应用中的配置信息剥离出来,存入 配置中心 统一管理。
1)什么是Nacos 配置中心
Nacos 除了可以做注册中心,还提供了配置中心,可以存储和管理 服务的配置文件以及key-value的其他数据。
如图所示,我们可以把微服务的配置文件 存储到配置中心,服务在启动时候会去配置中心中拉去最新的配置文件。
2)Nacos配置中心架构
服务端
1、服务端启动后通过NacosClient去配置中心获取配置数据
2、服务启动后,NacosClient会根据配置文件的key作为ID开启监听器,当监听到 配置中心的配置文件发生变动,会立即拉去最新的配置数据到服务端
用户端
用户可通过管理控制器 去修改配置文件
Nacos服务端
当用户修改配置文件后,节点会把修改的信息同步给集群中的其他节点并存储到持久化层(MySQL数据库)
3)Nacos配置中心核心源码入口点
package com.alibaba.nacos.api.config;
ConfigService
Nacos 核心API实验
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
| public class ConfigServerDemo {
public static void main(String[] args) throws NacosException, InterruptedException { String serverAddr = "localhost"; String dataId = "nacos-config-demo.yaml"; String group = "DEFAULT_GROUP"; Properties properties = new Properties(); properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr); ConfigService configService = NacosFactory.createConfigService(properties); String content = configService.getConfig(dataId, group, 5000); System.out.println(content); configService.addListener(dataId, group, new Listener() { @Override public void receiveConfigInfo(String configInfo) { System.out.println("===recieve:" + configInfo); }
@Override public Executor getExecutor() { return null; } });
configService.publishConfig(dataId,group,"common.age=30", ConfigType.PROPERTIES.getType());
Thread.sleep(3000); content = configService.getConfig(dataId, group, 5000); System.out.println(content);
} }
|
Spring Cloud集成Nacos配置中心
1)引入依赖
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> <relativePath/> </parent> <groupId>com.javaxing</groupId> <artifactId>NacosConfig</artifactId> <version>0.0.1-SNAPSHOT</version> <name>NacosConfig</name> <description>NacosConfig</description>
<properties> <spring-cloud.version>Hoxton.SR12</spring-cloud.version> <spring-cloud-alibaba.version>2.2.8.RELEASE</spring-cloud-alibaba.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.1.0.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
</dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
<dependencyManagement> <dependencies>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
|
2)配置bootstrap.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| spring: application: name: nacos-config
cloud: nacos: config: server-addr: 10.211.55.12:8848 file-extension: yaml discovery: server-addr: 10.211.55.12:8848
|
注意:必须使用 bootstrap 配置文件来配置Nacos Server 地址
application.yml作用域在于当前应用有效,bootstrap.yml系统级别的配置有效(一般采用远程配置的时候才会用到)。
3)启动服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.javaxing.nacosconfig;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication public class NacosConfigApplication {
public static void main(String[] args) throws InterruptedException { ConfigurableApplicationContext context = SpringApplication.run(NacosConfigApplication.class, args); while (true){ System.out.println(context.getEnvironment().getProperty("aaa")); Thread.sleep(3000); } } }
|
我们在启动服务时,循环打印出 配置中心的文件参数
启动成功后,会先去拉取 nacos-config 的配置文件,也会拉取nacos-config.yaml (因为我们设置了以结尾yaml的配置文件),所以会优先使用yaml
4)配置文件高级参数
4.1 逻辑隔离
Nacos配置中心的隔离模型和注册中心一样,分为Namespace 命名空间,Group 分组,Service 应用。
Namespace:公共命名空间 public
不同命名空间的节点是完全隔离开的,相互之间无法访问。一般用于不同环境的隔离,如 开发测试环境(dev)和生产环境(prod)的隔离。
Group:默认分组 DEFAULT_GROUP
不同的服务可以归类到同一个分组中,分组也能起到隔离的作用,不同的分组之间无法相互访问。
4.3 profile 指定多个配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| spring: application: name: nacos-config
cloud: nacos: config: server-addr: 10.211.55.12:8848 file-extension: yaml
discovery: server-addr: 10.211.55.12:8848 profiles: active: dev
|
新建一个nacos-config-dev.yaml
重启服务后,成功获取到了nacos-config-dev.yaml文件的参数
4.4 自定义namespace命名空间
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: application: name: nacos-config cloud: nacos: config: server-addr: 10.211.55.12:8848 file-extension: yaml namespace: 37731914-6c28-4265-a090-7a9391ed843d
|
如果我们指定了namespace,那么服务只会去对应的namespace中获取的配置文件。
namespace一般用于不同环境的分区隔离,如 dev开发环境、prod生产环境、uat测试环境等。
4.5 自定义Group分组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring: application: name: nacos-config cloud: nacos: config: server-addr: 10.211.55.12:8848 file-extension: yaml namespace: 37731914-6c28-4265-a090-7a9391ed843d group: DEFAULT_GROUP
|
默认分组:DEFAULT_GROUP
4.6 读取多个配置文件
Data ID:每一个配置文件的唯一标识
很多时候配置文件的参数是可以共用的,如 redis、mysql、rabbitMQ,没必要在每个配置文件都配上这样的参数。
那么我们就可以在一个微服务上面读取多个配置,也就是可以配置多个Data ID。
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
| spring: application: name: nacos-config
cloud: nacos: config: server-addr: 10.211.55.12:8848 file-extension: yaml namespace: 37731914-6c28-4265-a090-7a9391ed843d group: DEFAULT_GROUP shared-configs: - data-id: common-mysql.yaml group: SPRING_CLOUD_EXAMPLE_GROUP
- data-id: common-redis.yaml group: SPRING_CLOUD_EXAMPLE_GROUP
extension-configs: - data-id: nacos-config-advanced.yaml group: SPRING_CLOUD_EXAMPLE_GROUP refresh: true
- data-id: nacos-config-base.yaml group: SPRING_CLOUD_EXAMPLE_GROUP refresh: true
|
我们需要读取多个配置文件的话,可以用共享配置和扩展配置两种方式,扩展配置的优先级高于共享配置。
两种方式看不出本质差别;除了优先级不同以外,也没有其他差别。
配置文件的优先级
Nacos Config可以通过3个方式来从Nacos中拉去配置:
- A: 通过 spring.cloud.nacos.config.shared-configs 支持多个共享 Data Id 的配置
- B: 通过 spring.cloud.nacos.config.ext-config.data-id 的方式支持多个扩展 Data Id 的配置
- C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置,如nacos-config-dev.yaml
当三种方式共同使用时,他们的一个优先级关系是:A < B < C 。
新版本Nacos配置方式
在2.2.0之后的版本,有新的方式来引入 多个配置文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| spring: application: name: nacos-config
cloud: nacos: config: server-addr: 10.211.55.12:8848 file-extension: yaml namespace: 37731914-6c28-4265-a090-7a9391ed843d group: DEFAULT_GROUP import: - optional:nacos:application-dev.yml - optional:nacos:application-common-dev.yml - optional:nacos:application-common-dev.yml?group=group_01 - optional:nacos:application-common-dev.yml?group=group_01&refreshEnable=false
|
5)@RefreshScope实现动态感知
@Value注解可以获取到配置中心的值,但是无法动态感知修改后的值,因为当我们controller去访问的时候,实际上访问的是controller的bean,这个bean的单例对象池里面的属性 在初始化时已经赋值了。
5.1 获取value注解,无法动态刷新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.javaxing.nacosconfig.controller;
import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
@RestController public class TestController { @Value("${aaa}") private String aaaStr; ;
@GetMapping("/test") public void Test(){ System.out.println("配置文件的参数值:"+aaaStr); } }
|
Nacos 配置中心修改aaa的值为10
再次访问controller
当我们修改完nacos配置文件后,再次执行controller,会发现这个值并没有动态的发生改变。
因为当我们启动服务时,配置中心的参数会在容器初始化的时候,跟随controller的Bean 初始化时,存入到bean的单例变量池。
5.2 增加注解实现动态感知
1 2 3 4 5 6 7 8 9 10 11
| @RestController @RefreshScope public class TestController { @Value("${aaa}") private String aaaStr; ;
@GetMapping("/test") public void Test(){ System.out.println("配置文件的参数值:"+aaaStr); } }
|
访问controller,当前的value是10:
我们在nacos修改参数为 30
再次请求controller
如图所示,在不重启服务端的情况下,我们再次请求controller后,拿到的value是最新的30。
并且通过日志可以发现,SpringBoot已经重启了。
5.3 @RefreshScope 导致@Scheduled定时任务失效问题
当利用@RefreshScope刷新配置后会导致定时任务失效,因为当我们刷新配置后,SpringBoot容器已经重启了一次,容器里面的Bean都会被清空。而重启后的是不存在该bean,那么定时任务也会失效。
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
| package com.javaxing.nacosconfig.controller;
import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent; import org.springframework.context.ApplicationListener; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
@RestController @RefreshScope public class TestController implements ApplicationListener<RefreshScopeRefreshedEvent> { @Value("${aaa}") private String aaaStr; ;
@GetMapping("/test") public void Test(){ System.out.println("配置文件的参数值:"+aaaStr); }
@Scheduled(cron = "*/3 * * * * ?") public void execute() { System.out.println("定时任务正常执行。。。。。。"); }
@Override public void onApplicationEvent(RefreshScopeRefreshedEvent refreshScopeRefreshedEvent) { this.execute(); } }
|
我们可以做一个动态刷新监听,当刷新后 就重新执行 定时任务。
但是实际上,并不推荐 动态刷新,因为刷新时 会刷新bean容器的数据,会导致一些不可预料的问题。