01 Nacos配置中心实战
引入依赖
<!--nacos配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
配置文件的优先级 从高到低
# ${spring.application.name}-${profile}.${file-extension:properties}
#${spring.application.name}.${file-extension:properties}
#${spring.application.name}
#extensionConfigs nacos.yml
#sharedConfigs 多个微服务公共配置 redis
@RestController
@RefreshScope // 此注解可以感知value变化
public class TestController {
@Value("${common.age}")
private String age;
@GetMapping("/common")
public String hello() {
return age;
}
}
在bootstrap.properties文件中配置,可以配置profile/namespace/group/dataId(直接指定文件名),dataId也可以是共享sharedConfigs也可以是独立extensionConfigs
spring.application.name=nacos-config
# 配置中心地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
# 关闭配置中心
#spring.cloud.nacos.config.enabled = false
# dataid 为 yaml 的文件扩展名配置方式
# `${spring.application.name}.${file-extension:properties}`
spring.cloud.nacos.config.file-extension=yaml
#profile粒度的配置 `${spring.application.name}-${profile}.${file-extension:properties}`
# nacos-config-prod.yaml
spring.profiles.active=prod
#自定义 namespace 的配置
spring.cloud.nacos.config.namespace=39e1e969-15f9-46d2-832d-fa052da55377
# 自定义 Group 的配置
spring.cloud.nacos.config.group=DEFAULT_GROUP
# 自定义 Data Id 的配置
#不同工程的通用配置 支持共享的 DataId redis
spring.cloud.nacos.config.sharedConfigs[0].data-id= common.yaml
spring.cloud.nacos.config.sharedConfigs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.sharedConfigs[0].refresh=true
# config external configuration
# 支持一个应用多个 DataId 的配置 nacos.yml mybatis.yml
spring.cloud.nacos.config.extensionConfigs[0].data-id=nacos.yaml
spring.cloud.nacos.config.extensionConfigs[0].group=REFRESH_GROUP
spring.cloud.nacos.config.extensionConfigs[0].refresh=true
springboot 和nacos整合
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-actuator</artifactId>
<version>${nacos-config-spring-boot.version}</version>
</dependency>
application.properties配置文件就这一句就够了 nacos.config.server-addr=127.0.0.1:8848
@SpringBootApplication
// 配置使用哪个dataId做为数据源
@NacosPropertySource(dataId = "example", autoRefreshed = true)
public class NacosConfigApplication {
public static void main(String[] args) {
SpringApplication.run(NacosConfigApplication.class, args);
}
}
@Controller
@RequestMapping("config")
public class ConfigController {
// 这个 获取配置的值
@NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
private boolean useLocalCache;
@RequestMapping(value = "/get", method = GET)
@ResponseBody
public boolean get() {
return useLocalCache;
}
}
02 Nacos配置中心架构剖析
03 Nacos Config client源码分析
入口:接口 核心方法
多个配置优先级是怎么样的
springboot加载属性配置:org.springframework.boot.env.PropertySourceLoader接口有两个实现类
把某个实现类的load方法作为他的入口 org.springframework.boot.env.PropertiesPropertySourceLoader#load
启动过程中,也是走了SpringApplication的run方法,发布了ApplicationEnvironmentPreparedEvent 环境准备事件 ,org\springframework\cloud\bootstrap\BootstrapApplicationListener监听器触发,过程中又调回springboot的方法,ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); 又把事件传给了springboot的监听器ConfigFileApplicationListener,他会加载所有的配置文件,过程中 PropertiesPropertySourceLoader#load方法先加载bootstrap.properties,再加载application.properties...
04 client端是如何从配置中心获取配置的
获取配置的主要方法是 NacosConfigService 类的 getConfig 方法,通常情况下该方法直接从本地文件中取得配置的值,如果本地文件不存在或者内容为空,则再通过 HTTP GET 方法从远端拉取配置,并保存到本地快照中。当通过 HTTP 获取远端配置时,Nacos 提供了两种熔断策略,一是超时时间,二是最大重试次数,默认重试三次。
05 配置中心配置发生变更Client是如何感知的
所有的配置文件加载完成之后,会给所有的dataid添加一个相应的listener,后台会有一个线程定时去检查配置文件信息,发现文件md5发生改变后,就会触发监听器 的方法,方法内部有会发布RefreshEvent,这个RefreshEventListener会触发ContextRefresher的refresh,刷新环境,替换之前的环境, 注解@RefreshScope修饰的bean会存在一个容器里,旧的bean会被remove,替换成新bean
06 Nacos Config Server源码分析
public class ConfigServerDemo {
public static void main(String[] args) throws NacosException, InterruptedException {
String serverAddr = "localhost:8848";
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("感知配置变化:" + configInfo);
}
@Override
public Executor getExecutor() {
return null;
}
});
//发布配置 发送properties格式
configService.publishConfig(dataId,group,"common.age=30", ConfigType.PROPERTIES.getType());
Thread.sleep(3000);
//从配置中心拉取配置
content = configService.getConfig(dataId, group, 5000);
System.out.println(content);
Thread.sleep(Integer.MAX_VALUE);
}
}
07 集群架构下其他节点是如何同步配置数据的
服务端启动时就会依赖 DumpService 的 init 方法,从数据库中 load 配置存储在本地磁盘上,并将一些重要的元信息例如 MD5 值缓存在内存中。服务端会根据心跳文件中保存的最后一次心跳时间,来判断到底是从数据库 dump 全量配置数据还是部分增量配置数据(如果机器上次心跳间隔是 6h 以内的话)。
全量 dump 当然先清空磁盘缓存,然后根据主键 ID 每次捞取一千条配置刷进磁盘和内存。增量 dump 就是捞取最近六小时的新增配置(包括更新的和删除的),先按照这批数据刷新一遍内存和文件,再根据内存里所有的数据全量去比对一遍数据库,如果有改变的再同步一次,相比于全量 dump 的话会减少一定的数据库 IO 和磁盘 IO 次数。
如果想改mysql的配置也立即更新到客户端,需要写一个监听器监听变化发布一个ConfigDataChangeEvent事件,否则不重启服务端是不会感知到的。