Nacos的配置中心
先来聊聊配置中心是什么,以及为什么要使用配置中心。简单的说,配置中心是可以集中、灵活、动态的管理系统中的各种配置参数的配置管理产品,例如增、删、改、查功能开关、数据库连接配置、服务请求地址等。所谓集中,就是有统一管理的平台;灵活,不需要修改代码,做到自动匹配赋值、配置隔离;动态,不需要通过重启服务来使变更生效,主动推送或拉取变更的值。
对于配置参数,早期很传统的做法是通过程序硬编码的方式,将参数值写到代码中,如果要改变参数值,不仅要修改代码,还需要重新部署。重新部署倒是勉强可以接受,修改代码会导致代码混乱,你想想如果不同的部署环境有N多不同的配置参数值,是不是每部署一个环境就需要改一次代码,所以这个坚决不能忍受。为了解决这个问题,将配置参数放到配置文件或数据库中,在需要修改参数值时直接修改即可,不需要改动代码,但有些时候仍然需要重新部署,因为你不可能把所有参数都放到数据库中配置,而且频繁读库,参数变更也不能及时生效,再者说,文件或数据库的方式管理起来也不是很方便,除非开发一个管理平台。所以,配置中心应运而生,可以集中、灵活、动态的管理这些参数配置。
Nacos提供了一个简洁易用管理控制台,通过它可以管理所有的服务和应用的配置。Nacos的动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。它还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
Nacos配置中心中的相关概念
配置项:通常以key-value的形式存在,例如:
database.trade.connect.url=jdbc:mysql://127.0.0.1:3306/trade。
配置集:一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。
配置集ID:即某个配置集的ID,使用Data ID表示。一个系统或者应用可以包含多个配置集,每个配置集推荐使用一个有意义的名称标识,并且要保证全局唯一,例如trade-datasource.properties。推荐Data ID采用类Java包的命名规则保证全局唯一性,例如com.abc.trade.datasource.properties,需要注意的是Nacos默认支持JSON、XML、YAML和Properties格式的配置项解析,所以如果Data ID的名称中包含.,它的名称后缀要以.json/.xml/.yaml/.properties结尾,如果Data ID的名称中不包含.,Nacos默认使用.properties格式解析配置项。
配置分组:通过一个有意义的字符串对配置集进行分组,从而区分Data ID相同的配置集,例如Payment、Trade等。在Nacos上创建一个配置时,如果未填写配置分组的名称,则使用DEFAULT_GROUP作为默认的配置分组名称。
命名空间(Namespace):不同的命名空间下,可以存在相同的配置分组或 Data ID的配置。 主要用于不同环境的配置的区分隔离,如果未明确指定,则默认的命名空间是public。例如测试环境和生产环境的配置是不同的,就可以使用不同的命名空间来区分隔离不同的配置,如测试环境的命名空间设置为dev,生产环境的命名空间设置为prod。
Nacos配置中心中的一个配置项由命名空间+配置分组+配置集ID+配置项key唯一确定。
![27e2d6364bee0ef3822c8403ad28d262.png](https://i-blog.csdnimg.cn/blog_migrate/a7ad7a9e43163dbd2d42619b3214f9d8.jpeg)
对于上面介绍的概念,这里举个例子,例如某交易系统的数据库连接配置,测试环境的命名空间是dev,生产环境的命名空间是prod,分组使用Trade来表示,Data ID使用trade-datasource.properties来表示,里面的配置项包含database.trade.connect.url=jdbc:mysql://127.0.0.1:3306/trade。
Spring结合Nacos作为配置中心
项目使用了Spring框架,而没有使用Spring Boot、Spring Cloud,在添加Nacos相关jar包依赖时,只需要添加nacos-spring-context,这里以maven为例展示nacos-spring-context的依赖信息。
com.alibaba.nacos nacos-spring-context 0.3.6
首先,通过初始化相关参数值启用Nacos,例如Nacos服务的地址、用户名、密码、命名空间等,这一步可以通过注解的方式实现,也可以通过在xml中配置的方式实现。
注解方式需要新建NacosConfiguration.java,当然也可以是其它类名,并在这个类上使用@EnableNacosConfig注解指明要连接的Nacos服务的地址、用户名、密码和命名空间,当然还有其它属性可以设置,例如:
@Component@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848", username = "nacos", password = "nacos", namespace = "dev"))public class NacosConfiguration {}
xml配置方式,需要先在xml顶部添加nacos的xml命名空间和相应的xsd信息。
xmlns:nacos="http://nacos.io/schema/nacos"xsi:schemaLocation="http://nacos.io/schema/nacos http://nacos.io/schema/nacos.xsd"
然后使用如下配置启用Nacos并设置相关参数值。
最简单的使用:获取配置中心中的某个配置的值,如果你使用注解方式开启Nacos,需要在上面说到的NacosConfiguration.java上添加@NacosPropertySource注解指明要用到的Data ID、配置分组和变更时是否自动刷新,如下代码片段:
@NacosPropertySource(dataId = "com.example.trade.datasource.properties", groupId = "Trade", autoRefreshed = true)
如果你使用xml方式,相应的需要在Spring的xml中添加nacos:property-source元素,代码片段如下:
然后再使用@NacosValue注解将需要获取的配置参数注入到某个属性上,这里为了更好的解释说明,写了一个HelloController,具体代码如下:
@Controller@RequestMappingpublic class HelloController { @NacosValue(value = "${useCache:false}", autoRefreshed = true) private Boolean useCache; @RequestMapping(value = "/hi", method = RequestMethod.GET) @ResponseBody public String sayHi(){ return "hi, " + useCache; }}
上面代码使用@NacosValue注解将配置中心的useCache参数值赋值给变量useCache,同时配置了autoRefreshed = true,表示配置中心的useCache值发生变更时自动刷新该属性值。本示例详细代码Github上搜wind7rui/nacos-demo,查阅nacos-demo的子工程nacos-config-spring-simple-demo。
如果要将配置中心的参数值注入到一个POJO的属性上,这里列举三种方法。
方法一,还是使用@NacosValue注解,在POJO的属性字段上标注,但需要在NacosConfiguration.java上添加@NacosPropertySource,或者在xml中配置nacos:property-source元素,同时需要配置Data ID、配置分组和变更时是否自动刷新属性值,示例片段代码如下:
@Component@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848", username = "nacos", password = "nacos", namespace = "dev"))@NacosPropertySource(dataId = "com.example.trade.datasource.properties", groupId = "Trade", autoRefreshed = true)public class NacosConfiguration {}@Componentpublic class DbConnectProperties { @NacosValue(value = "${datasource.connect.url}") private String url; @NacosValue(value = "${datasource.connect.username}") private String username; @NacosValue(value = "${datasource.connect.password}") private String password; // 省略getter、setter和toString方法
方法二,在xml中配置。这种方法需要在对应的POJO中编写对应属性的getter和setter方法,同样需要在NacosConfiguration.java上添加@NacosPropertySource,或者在xml中配置nacos:property-source元素,同时需要配置Data ID、配置分组和变更时是否自动刷新属性值,示例片段代码如下:
@Component@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848", username = "nacos", password = "nacos", namespace = "dev"))@NacosPropertySource(dataId = "com.example.trade.datasource.properties", groupId = "Trade", autoRefreshed = true)public class NacosConfiguration {}public class DbProperties { private String url; private String username; private String password; // 省略getter、setter和toString方法
方法三,使用@NacosConfigurationProperties注解。编写对应POJO类的属性的getter、setter方法,然后使用@NacosConfigurationProperties注解标注该类,同时设置注解中的属性值,例如prefix-配置项key前缀、配置分组、Data Id、是否自动刷新,示例片段代码如下:
@Component@NacosConfigurationProperties(prefix = "datasource.connect", groupId = "Trade", dataId = "com.example.trade.datasource.properties", autoRefreshed = true)public class DatasourceProperties { private String url; private String username; private String password; // 省略getter、setter和toString方法
这种方式只需要结合@EnableNacosConfig注解,或在xml配置中开启Nacos配置就行。需要注意prefix这个属性,举个例子,如果配置中心有一个参数配置datasource.connect.username=admin,而POJO中的属性字段名是username,那么此时prefix就是datasource.connect,不需要加.,Nacos在参数映射时会自动加上.。
以上三种方法的详细代码Github上搜wind7rui/nacos-demo,查阅nacos-demo的子工程nacos-config-spring-pojo-demo。
当然真实的开发过程中,不可能只要有一个配置,即有多个配置集,此时可以使用多个@NacosPropertySource分别配置,例如:
@Component@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848", username = "nacos", password = "nacos", namespace = "dev"))@NacosPropertySource(dataId = "com.example.trade.datasource.properties", groupId = "Trade", autoRefreshed = true)@NacosPropertySource(dataId = "com.example.order.datasource.properties", groupId = "Order", autoRefreshed = true)@NacosPropertySource(dataId = "com.example.pay.datasource.properties", groupId = "Pay", autoRefreshed = true)public class NacosConfiguration {}
也可以使用@NacosPropertySources注解,它的value是一个@NacosPropertySource注解的数组,可以配置多个配置集,例如:
@Component@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848", username = "nacos", password = "nacos", namespace = "dev"))@NacosPropertySources({ @NacosPropertySource(dataId = "com.example.trade.datasource.properties", groupId = "Trade", autoRefreshed = true), @NacosPropertySource(dataId = "com.example.order.datasource.properties", groupId = "Order", autoRefreshed = true), @NacosPropertySource(dataId = "com.example.pay.datasource.properties", groupId = "Pay", autoRefreshed = true)})public class NacosConfiguration {}
学之多,而后知之少!朋友们【点赞+评论+转发】是我持续更新的最大动力,我们下期见!
往期推荐:
阿里开源组件Nacos实战操作之安装部署完整版
我画了25张图展示线程池工作原理和实现原理,建议先收藏再阅读
面向开发人员的Docker入门级实战,真香
这样的API网关查询接口优化,我是被迫的
Spring声明式事务处理的实现原理,来自面试官的穷追拷问
Spring框架你敢写精通,面试官就敢问@Autowired注解的实现原理
说实话,面试这么问Spring框架的问题,我真扛不住
面试被问为什么使用Spring Boot?答案好像没那么简单
没使用加号拼接字符串,面试官竟然问我为什么
都说ThreadLocal被面试官问烂了,可为什么面试官还是喜欢继续问
面试官一步一步的套路你,为什么SimpleDateFormat不是线程安全的