Nacos的自动刷新和多环境管理
自动刷新
所谓自动刷新,通俗说就是指当我们在Nacos配置中心管理界面修改之后,相应服务会自动读取到修改后的配置。
自动刷新的功能是默认开启的,测试如下:
修改主程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @SpringBootApplication public class NacosConfigSimpleApplication { public static void main(String[] args) throws InterruptedException { ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigSimpleApplication.class, args); while(true){ ConfigurableEnvironment environment = applicationContext.getEnvironment(); String username = environment.getProperty("user.name"); String age = environment.getProperty("user.age"); System.out.println("username:"+username+" | age:"+age); TimeUnit.SECONDS.sleep(1); } } }
|
测试结果
然后我们修改相应的配置文件的age字段的数据,可以看到Idea的控制输出信息:
关闭自动刷新
1 2
| spring.cloud.nacos.config.refresh.enabled = false
|
可以通过上述配置来关闭配置自动刷新。
我们可以看看源码:[默认为true]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class NacosRefreshProperties {
@Value("${spring.cloud.nacos.config.refresh.enabled:true}") private boolean enabled = true;
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; } }
|
Nacos的配置类:NacosConfigProperties
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
| @ConfigurationProperties(NacosConfigProperties.PREFIX) public class NacosConfigProperties {
public static final String PREFIX = "spring.cloud.nacos.config";
private String serverAddr; private String encode; private String group = "DEFAULT_GROUP"; private String prefix; private String fileExtension = "properties"; private int timeout = 3000; private String endpoint; private String namespace; private String accessKey; private String secretKey; private String contextPath; private String clusterName; private String name; private String sharedDataids; private String refreshableDataids; private List<Config> extConfig; private ConfigService configService;
public static class Config { private String dataId; private String group = "DEFAULT_GROUP"; private boolean refresh = false; }
public ConfigService configServiceInstance() {...} }
|
NacosConfig 自动配置:NacosConfigAutoConfiguration
1 2 3 4
| @Configuration @ConditionalOnProperty(name = "spring.cloud.nacos.config.enabled", matchIfMissing = true) public class NacosConfigAutoConfiguration {}
|
多环境profile管理
profile粒度控制
首先我们在Nocos控制页面配置两个不同环境的配置,如下:
nacos-config-develop.yaml:
1
| current.env: develop-env
|
nacos-config-product.yaml:
1
| current.env: product-env
|
修改主程序,增加读取环境类型的属性:
1 2 3 4 5 6 7 8 9 10 11 12
| public static void main(String[] args) throws InterruptedException { ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigSimpleApplication.class, args);
ConfigurableEnvironment environment = applicationContext.getEnvironment(); String username = environment.getProperty("user.name"); String age = environment.getProperty("user.age"); String env = environment.getProperty("current.env"); System.out.println("username:"+username+" | age:"+age +" | env:"+env); TimeUnit.SECONDS.sleep(1);
}
|
然后在配置bootstrap.properties配置文件指定激活环境:
几种激活方式可以查看:https://blog.csdn.net/ooyhao/article/details/100939089#Profile_176
1 2 3 4 5 6 7 8 9
| spring.application.name=nacos-config
spring.cloud.nacos.config.file-extension=yaml
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.profiles.active=develop
|
注意:${spring.profiles.active}当通过配置文件来指定的时候,必须放在bootstrap.properties文件中。
通过结果可以看出,读取到的配置有nacos-config.yaml和nacos-config-develop.yaml。
注意:此示例中我们通过spring.profile.active= <profilename>
的方式写死在配置文件中,而在真正的项目实施过程中,这个变量的值需要不同环境而有不同的值。这个时候通常的做法是通过 -Dspring.profiles.active=<profile>
参数指定其配置来达到环境间灵活的切换。 具体可以参考上述链接内容
总结:文件匹配规则如下(dataId),${spring.cloud.nacos.config.prefix}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
我们可以看看源码:
加载配置源码分析
NacosConfigProperties类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @ConfigurationProperties(NacosConfigProperties.PREFIX) public class NacosConfigProperties {
public static final String PREFIX = "spring.cloud.nacos.config";
private String serverAddr; private String encode; private String group = "DEFAULT_GROUP"; private String prefix; private String fileExtension = "properties"; private int timeout = 3000; private String endpoint; private String namespace; private String accessKey; private String secretKey; private String contextPath; private String clusterName; private String name; private String sharedDataids; private String refreshableDataids; }
|
上述删除了部分代码,但是我们可以看到,fileExtension的默认值是properties.所以,在前一节中,我们使用properties格式的配置文件时,是没有配置文件扩展类型的。
注意:上面的配置类中有prefix,并且按上述的文件匹配规则来看,我们应该加载不到nacos-config.yaml
文件的,但是测试结果是加载到了这个文件,而我们并没有配置前缀,所以可以推断出,模式是使用spring.application
属性。 我们查看源码可以看到原因:
NacosPropertySourceLocator类:我们粗略的看一下(源码恐怖,后续深入研究)
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
| @Order(0) public class NacosPropertySourceLocator implements PropertySourceLocator {
private static final String NACOS_PROPERTY_SOURCE_NAME = "NACOS"; private static final String SEP1 = "-"; private static final String DOT = "."; private static final String SHARED_CONFIG_SEPARATOR_CHAR = "[,]"; private static final List<String> SUPPORT_FILE_EXTENSION = Arrays.asList("properties","yaml", "yml");
@Override public PropertySource<?> locate(Environment env) {
String name = nacosConfigProperties.getName(); String dataIdPrefix = nacosConfigProperties.getPrefix(); if (StringUtils.isEmpty(dataIdPrefix)) { dataIdPrefix = name; } if (StringUtils.isEmpty(dataIdPrefix)) { dataIdPrefix = env.getProperty("spring.application.name"); }
CompositePropertySource composite = new CompositePropertySource( NACOS_PROPERTY_SOURCE_NAME);
loadSharedConfiguration(composite); loadExtConfiguration(composite); loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env); return composite; }
private void loadApplicationConfiguration( CompositePropertySource compositePropertySource, String dataIdPrefix, NacosConfigProperties properties, Environment environment) { String fileExtension = properties.getFileExtension(); String nacosGroup = properties.getGroup(); loadNacosDataIfPresent(compositePropertySource, dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true); for (String profile : environment.getActiveProfiles()) { String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension; loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, fileExtension, true); } } }
|
注意:通过上述代码分析,就知道为什么加载了nacos-config.yaml
和 nacos-config-develop.yaml
.
多环境Group管理
在没有自定义${spring.cloud.nacos.config.group}
配置的情况下,默认使用的是DEFAULT_GROUP
, 如果需要自定义,可以通过下面的配置来实现:
1
| spring.cloud.nacos.config.group=DEVELOP_GROUP
|
注意:该配置必须放在bootstrap.properties文件中,并且在添加配置时的值一定要和spring.cloud.nacos.config.group
的属性值一致。
默认配置
Develop配置
测试结果
1 2 3
|
username:欧阳 | age:23 | env:DEV
|
多环境namespace管理
概述
我们看一下官方时如何介绍namespace的:
用户进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的Group或Data ID的配置。Namespace的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
在配置文件中没有自定义namespace的时候,模式使用的是Nacos上Public作为namespace,如果我们希望自定义,可以通过${spring.cloud.nacos.config.namespace}
来配置。
默认命名空间
我们先看之前的默认namespace。
自定义命名空间
1
| spring.cloud.nacos.config.namespace= dc7fb953-fab6-4f98-95b9-e777d02cd683
|
注意:这个配置必须放在bootstrap.properties文件中。并且spring.cloud.nacos.config.namespace
配置的是namespace Id。而不是命名空间名称。并且这个命名空间id是不用自己生成的,只要在Nacos新建一个命名空间,管理页面就会自动产生一个字符串。在配置文件中配置时要注意选择相应的namespace,否则会读不到正确的配置。
这里为了保证配置的干净,我新建一个项目来测试。
完整配置
1 2 3 4 5 6 7 8
| spring.application.name=nacos-config-namespace
spring.cloud.nacos.config.group=ouYangGroup
spring.cloud.nacos.config.namespace=dc7fb953-fab6-4f98-95b9-e777d02cd683 spring.cloud.nacos.config.file-extension=yaml spring.cloud.nacos.config.server-addr=192.168.1.104:8848
|
Nacos配置
测试结果
主程序:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @SpringBootApplication public class NacosConfigNamespaceApplication {
public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigNamespaceApplication.class, args); ConfigurableEnvironment environment = applicationContext.getEnvironment(); String username = environment.getProperty("user.username"); String password = environment.getProperty("user.password"); System.out.println("username:"+username+" | password:"+password); } }
|
测试结果:
1
| username:admin | password:123456
|