重要知识点
- Nacos属性的简单使用
- 将SpringBoot中的所有配置全部放入到Nacos中
- 开发人创建单独的命名空间,修改互不影响
- Nacos经常变动的配置抽离到外部文件中
将项目中的所有配置全部放到到
1. 首先引入包
<!-- nacos 接入--><!-- https://mvnrepository.com/artifact/com.alibaba.boot/nacos-config-spring-boot-starter --><dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>最新版本号</version></dependency>
2. 配置Nacos的配置文件
- 主配置; 主要是加载
静态配置
文件的; SpringBoot在启动的时候会先去Nacos中读取配置文件然后加载到Environment中; 静态配置不启用自动刷新;
#(下面的配置中只需要吧对应的data-ids、group、data-id 、server-addr、namespace修改为对应数据)#
## -----------------静态文件配置(启动的时候最优先加载 log-enable:true)-------------- ##
nacos:
config:
bootstrap:
log-enable:true # 支持日志级别的加载时机(如果需要集成dubbo,请使用此配置加载时机)
enable:true # 设置参数nacos.config.bootstrap.enable=true,开启配置预加载功能
max-retry:10 # 主配置 最大重试次数
auto-refresh:false # 主配置 是否开启自动刷新 (false:不监听属性变化,true:监听属性变化,但是对应的属性注解上也必须设置autoRefreshed =true才可以实时更新)
config-retry-time:3000 # 主配置 重试时间
config-long-poll-timeout:30000 # 主配置 配置监听长轮询超时时间
enable-remote-sync-config:false # 主配置 开启注册监听器预加载配置服务(除非特殊业务需求,否则不推荐打开该参数)
#允许nacos上的配置优先于本地配置; 意思是:如果nacos配置了某属性,然后在本地的application.yml配置了相同属性;那么会以nacos配置的优先;否则是本地的优先
remote-first:true
# 主配置 data-ids (可以配置多个,如果多个配置文件中有相同的 属性 则优先取最前面的值)
data-ids: application-static.properties,logback-static.xml
group:PROJECT_EXAMPLE # 主配置 group-id
type: yaml # 主配置 配置文件类型
server-addr:127.0.0.1:8848
namespace: # 命名空间
name: nacos
password: nacos
上面的静态配置修改最后面的几个属性就行了;
- 动态配置 动态配置有两种配置 一种是在yml配置文件中配置
nacos:
config:
ext-config[0]:
data-id: dynamic.properties
group:PROJECT_EXAMPLE
#namespace: # 命名空间 该属性如果为空 或者注释该属性 会继承主属性的命名空间
# 该属性不继承上面的主配置 是否开启自动刷新 (false:不监听属性变化,true:监听属性变化,但是对应的属性注解上也必须设置autoRefreshed =true才可以实时更新)
auto-refresh :true
type: properties # 类型 {@linkcom.alibaba.nacos.api.config.ConfigType}
## 如果还想加载其他的配置 copy一下 数组改成1 例如ext-config[1]
ext-config[1]:
data-id: dynamic.yaml
group:PROJECT_EXAMPLE
#namespace: # 命名空间 该属性如果为空 或者注释该属性 会继承主属性的命名空间
# 该属性不继承上面的主配置 是否开启自动刷新 (false:不监听属性变化,true:监听属性变化,但是对应的属性注解上也必须设置autoRefreshed =true才可以实时更新)
auto-refresh:true
type: yaml # 类型 {@linkcom.alibaba.nacos.api.config.ConfigType}
一种用注解的形式@NacosPropertySource 例如上面的动态配置跟下面效果一样
@NacosPropertySource(dataId ="dynamic.properties",groupId ="PROJECT_EXAMPLE",type =ConfigType.PROPERTIES,autoRefreshed =true)@NacosPropertySource(dataId ="dynamic.yaml",groupId ="PROJECT_EXAMPLE",type =ConfigType.YAML,autoRefreshed =true)
两者的区别: @NacosPropertySource不可以单独指定namespace; 配置文件的方式可以单独指定namespace ; 如果他们都不指定的话,默认继承自 主配置中的namespace配置
3.Nacos的简单应用
3.1 使用@NacosConfigurationProperties将配置绑定到对象中
例子:
/**
* @author shirenchuang
* @date 2020/10/20 9:56 上午
*
* 将配置中的 list 和listMap 解析并绑定到这个对象中
* 并可以使用 @Autowired注解使用这个对象
*
* nacos中的配置:
*
* test.list:
* - 1
* - 2
* - 3
* - 4
* test.listMap:
* key-1:
* - 1
* - 2
* - 3
* - 4
* key-2:
* - aa
* - dd
* - ee
* - rr
*
*
*/@NacosConfigurationProperties( prefix ="test1",dataId ="test.yaml",groupId ="PROJECT_EXAMPLE",type =ConfigType.YAML, autoRefreshed =true)@ConfigurationpublicclassApple{privateList<String> list;privateMap<String,List<String>> listMap;publicList<String>getList(){return list;}publicvoidsetList(List<String> list){this.list = list;}publicMap<String,List<String>>getListMap(){return listMap;}publicvoidsetListMap(Map<String,List<String>> listMap){this.listMap = listMap;}@OverridepublicStringtoString(){return"Apple{"+"list="+ list +", listMap="+ listMap +'}';}}
使用的时候就直接用注解
@Autowired
可以直接使用
@AutowiredprivateApple apple;
3.2 使用@NacosValue获取属性
// 是否自动刷新属性 必须在每个属性上都要标注@NacosValue(value ="${name:66}",autoRefreshed =true)privateString name;
如果属性值不存在就取 冒号 后面的默认值;
3.3 也可以使用@Value来获取Nacos配置中的属性值
@NacosValue(value ="${spring.datasource.url}",autoRefreshed =true)privateString url;@Value(value ="${spring.datasource.url}")privateString url2;
例如上面的
spring.datasource.url
的属性是配置在nacos中的;但是上面两个注解都正常打印出来了它的值,为什么呢?
@Value是从Spring容器中的Environment中获取对应的属性值,但是在启动Nacos的时候就把数据给加载到了Environment中去了; 所以通过@Value也能获取到属性值; 但是它跟@NacosValue的区别是, 它不能够实时刷新数据; 它的值一直都是启动时候第一遍加载的数据
所以我们也可以用@Value来获取我们在Nacos中配置的静态数据;作用是一样的 【SpringBoot】配置文件的加载与属性值的绑定
4.将Nacos一部分配置移动到外部文件中
我们在开发过程中,会经常涉及到配置文件的改动; 还有发布的时候不同环境用不同的配置; 这些配置写在项目的属性文件里面不太妥当; 最好是能够单独拎出来;
例如上面主配置中的 几个属性在不同环境中会经常频繁改动;那我们把他们单独拎出来存放到外部配置文件中;
Spring中读取外部配置文件的方式有很多;但是有一点很重要;就是加载时机的问题 例如
@PropertySource()
这个注解基本上是等容器都启动完成的时候才去解析的; 那么我们启动项目的时候是一开始就加载了Nacos的; 就必须我们在加载Nacos的配置文件之前就必须把Nacos需要的配置数据准备好并加载到
Environment
中去; 相关知识点可以参考: 【Spring Boot 四】启动之准备系统环境environmentPrepared 【SpringBoot】SpringBoot启动流程图和扩展点说明
那么最终决定我们可以选择 实现一个
EnvironmentPostProcessor
扩展类;
NacosEnvPostProcessor扩展类
importorg.springframework.boot.SpringApplication;importorg.springframework.boot.env.EnvironmentPostProcessor;importorg.springframework.boot.logging.DeferredLog;importorg.springframework.context.ApplicationEvent;importorg.springframework.context.ApplicationListener;importorg.springframework.core.Ordered;importorg.springframework.core.env.ConfigurableEnvironment;importorg.springframework.core.env.MutablePropertySources;importorg.springframework.core.env.PropertySource;importorg.springframework.core.env.StandardEnvironment;importorg.springframework.core.io.DefaultResourceLoader;importorg.springframework.core.io.Resource;importorg.springframework.core.io.ResourceLoader;importorg.springframework.core.io.support.DefaultPropertySourceFactory;importorg.springframework.core.io.support.EncodedResource;importorg.springframework.core.io.support.PropertySourceFactory;importorg.springframework.util.StringUtils;importjava.io.IOException;/**
* @author shirenchuang
* @date 2020/7/22 4:58 下午
*
* 这个优先级必须要比 NacosConfigEnvironmentProcessor 的优先级高
* 不然的话 NacosConfigEnvironmentProcessor 执行的时候 会取不到 Nacos的这几个配置属性
* 将文件中的属性放到 系统环境变量中; 优先级只会比StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME低
*/importorg.springframework.boot.SpringApplication;importorg.springframework.boot.env.EnvironmentPostProcessor;importorg.springframework.boot.logging.DeferredLog;importorg.springframework.context.ApplicationEvent;importorg.springframework.context.ApplicationListener;importorg.springframework.core.Ordered;importorg.springframework.core.env.ConfigurableEnvironment;importorg.springframework.core.env.MutablePropertySources;importorg.springframework.core.env.PropertySource;importorg.springframework.core.env.StandardEnvironment;importorg.springframework.core.io.DefaultResourceLoader;importorg.springframework.core.io.Resource;importorg.springframework.core.io.ResourceLoader;importorg.springframework.core.io.support.DefaultPropertySourceFactory;importorg.springframework.core.io.support.EncodedResource;importorg.springframework.core.io.support.PropertySourceFactory;importorg.springframework.util.StringUtils;importjava.io.IOException;/**
* @author shirenchuang
* @date 2020/7/22 4:58 下午
* 在最初的时候将 外部配置文件属性加载到容器中
*
* 这个优先级必须要比 NacosConfigEnvironmentProcessor 的优先级高
* 不然的话 NacosConfigEnvironmentProcessor 执行的时候 会取不到 Nacos的这几个配置属性
* 将文件中的属性放到 系统环境变量中; 优先级只会比StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME低
*/publicclassExternalFilePostProcessorimplementsEnvironmentPostProcessor,ApplicationListener<ApplicationEvent>,Ordered{/**
* 这个时候Log系统还没有初始化 使用DeferredLog来记录 并在onApplicationEvent进行回放
* */privatestaticfinalDeferredLogLOGGER=newDeferredLog();privateResourceLoader resourceLoader =newDefaultResourceLoader();@OverridepublicintgetOrder(){return0;}/**
* 将文件中的nacos配置文件 加载到 environment中;
* 方便Nacos可以拿到 静态配置
*
* @param environment
* @param application
*/@OverridepublicvoidpostProcessEnvironment(ConfigurableEnvironment environment,SpringApplication application){String filePath = environment.getProperty("nacos_file_path");if(StringUtils.isEmpty(filePath)){LOGGER.info("\n [----未配置外部属性路径-----] \n");return;}String resolvedLocation = environment.resolveRequiredPlaceholders(filePath);
resolvedLocation ="file:"+resolvedLocation;PropertySourceFactory factory =newDefaultPropertySourceFactory();Resource resource =this.resourceLoader.getResource(resolvedLocation);try{addPropertySource(factory.createPropertySource(filePath,newEncodedResource(resource)),environment);}catch(IOException e){LOGGER.error(" 外部配置路径 - Properties location ["+ filePath +"] not resolvable: "+ e.getMessage());}}privatevoidaddPropertySource(PropertySource<?> propertySource,ConfigurableEnvironment environment){MutablePropertySources propertySources = environment.getPropertySources();//添加到 systemEnvironment 优先级只比 系统属性 和命令行属性等等的低
propertySources.addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, propertySource);}@OverridepublicvoidonApplicationEvent(ApplicationEvent event){LOGGER.replayTo(ExternalFilePostProcessor.class);}}
然后配置一下
spring.factories
;
org.springframework.boot.env.EnvironmentPostProcessor=com.daimler.example.service.common.NacosEnvPostProcessor
相关知识点 【SpringBoot 二】spring.factories加载时机分析
然后本地创建一个文件
在yml中配置文件路径
#nacos 的基本配置(放在服务器本地文件上, 包含 nacos.config.server-addr、 nacos.config.namespace、 username、password)
nacos_file_path:/**/**/nacos_static/project_example-nacos.properties
Spring中实现上面的功能没有那么复杂
@EnableNacosConfig(globalProperties =@NacosProperties(username ="${nacos.config.username}", password ="${nacos.config.password}",
serverAddr ="${nacos.config.server-addr}",namespace ="${nacos.config.namespace}"))@NacosPropertySource(dataId ="dynamic.yaml",groupId ="PROJECT_EXAMPLE",type =ConfigType.YAML,autoRefreshed =true)publicclassNacosConfig{}@Configuration@PropertySource(value ="file:/etc/nacos.properties")@ComponentScan(basePackages ="com.xx")@Import( value ={NacosConfig.class})publicclassSpringConfig{}
然后外部配置文件配置
5.每个开发人员一套自己的配置
在本地开发过程中,我们可能会经常修改配置文件;但可能改了之后会影响到别人;就有这样的需求;我改配置的时候 只影响我自己;
我们可以看到上面的配置中 有一个配置
nacos.config.namespace=
; 这个是命名空间;通过这样一个属性我们可以应用不同的配置;
具体用法
- 新建一个属于自己的命名空间
- 将需要克隆的配置 从指定空间克隆到自己刚刚创建的空间
- 将自己本地nacos属性配置的
namespace
改成自己刚刚创建的命名空间id(注意是 ID
) - 重新启动,搞定!
完整的yml配置
#nacos 的基本配置(放在服务器本地文件上, 包含 nacos.config.server-addr、 nacos.config.namespace、 username、password)
nacos_file_path:/**/**/nacos_static/project_example-nacos.properties
#(下面的配置中只需要吧对应的data-ids、group、data-id 修改为对应数据)#
## -----------------静态文件配置(启动的时候最优先加载 log-enable:true)-------------- ##
nacos:
config:
bootstrap:
log-enable:true # 支持日志级别的加载时机(如果需要集成dubbo,请使用此配置加载时机)
enable:true # 设置参数nacos.config.bootstrap.enable=true,开启配置预加载功能
max-retry:10 # 主配置 最大重试次数
auto-refresh:false # 主配置 是否开启自动刷新 (false:不监听属性变化,true:监听属性变化,但是对应的属性注解上也必须设置autoRefreshed =true才可以实时更新)
config-retry-time:3000 # 主配置 重试时间
config-long-poll-timeout:30000 # 主配置 配置监听长轮询超时时间
enable-remote-sync-config:false # 主配置 开启注册监听器预加载配置服务(除非特殊业务需求,否则不推荐打开该参数)
#允许nacos上的配置优先于本地配置; 意思是:如果nacos配置了某属性,然后在本地的application.yml配置了相同属性;那么会以nacos配置的优先;否则是本地的优先
remote-first:true
# 主配置 data-ids (可以配置多个,如果多个配置文件中有相同的 属性 则优先取最前面的值)
data-ids: 静态配置1,静态配置2,logback.xml
group: 自己的group # 主配置 group-id
type: yaml # 主配置 配置文件类型
## ---------------如果 使用配置方式就是下面的; 如果用@NacosPropertySource注解方式就删掉下面的 --------------------------- ##
ext-config[0]:
data-id: 自己的data-id
group: 自己的group
#namespace: # 命名空间 该属性如果为空 或者注释该属性 会继承主属性的命名空间
# 该属性不继承上面的主配置 是否开启自动刷新 (false:不监听属性变化,true:监听属性变化,但是对应的属性注解上也必须设置autoRefreshed =true才可以实时更新)
auto-refresh :true
type: properties # 类型 {@linkcom.alibaba.nacos.api.config.ConfigType}
## 如果还想加载其他的配置 copy一下 数组改成1 例如ext-config[1]
ext-config[1]:
data-id: 自己的data-id
group: 自己的group
#namespace: # 命名空间 该属性如果为空 或者注释该属性 会继承主属性的命名空间
# 该属性不继承上面的主配置 是否开启自动刷新 (false:不监听属性变化,true:监听属性变化,但是对应的属性注解上也必须设置autoRefreshed =true才可以实时更新)
auto-refresh:true
type: yaml # 类型 {@linkcom.alibaba.nacos.api.config.ConfigType}
外部配置文件
/**/**/nacos_static/project_example-nacos.properties
# 主配置服务器地址
nacos.config.server-addr=127.0.0.1:8848
nacos.config.username=nacos
nacos.config.password=nacos
# 命名空间 (空为默认的public)
nacos.config.namespace=
版权归原作者 zhangjunli 所有, 如有侵权,请联系我们删除。