有道无术,术尚可求,有术无道,止于术。
前言
在很早之前我们使用Nacos 1.3.2 搭建了配置中心,自从发布2.0版本以来,以及Spring Boot 、Cloud 持续发布,升级到Nacos2.x 发现了一些升级需要注意的问题,所以写这篇文档闭坑,顺便讲解下如何实现动态刷新配置。
集成Nacos 2.x配置中心
首先按照之前的文档安装Nacos 2.x 以及升级到最新客户端。
Nacos系列(15)-Nacos2.0.3安装
1. 环境搭建
添加配置中心依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
添加bootstrap.yml 文件,该文件会在应用启动时最先加载,并在文件中添加配置中心:
server:
port: 9005
spring:
application:
name: app-service001
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
enabled: true
在Nacos 控制台,添加一个app-service001.yaml 配置文件,内容如下:
2. 解决Param ‘serviceName’ is illegal, serviceName is blank
首先启动的时候,控制台打印了以下错误信息:
java.lang.IllegalArgumentException: Param 'serviceName' is illegal, serviceName is blank
at com.alibaba.nacos.api.naming.utils.NamingUtils.getGroupedName(NamingUtils.java:47) ~[nacos-client-2.1.0.jar:na]
at com.alibaba.nacos.client.naming.event.InstancesChangeNotifier.registerListener(InstancesChangeNotifier.java:55) ~[nacos-client-2.1.0.jar:na]
at com.alibaba.nacos.client.naming.NacosNamingService.subscribe(NacosNamingService.java:392) ~[nacos-client-2.1.0.jar:na]
at com.alibaba.cloud.nacos.discovery.NacosWatch.start(NacosWatch.java:134) ~[spring-cloud-starter-alibaba-nacos-discovery-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) [spring-context-5.3.8.jar:5.3.8]
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) [spring-context-5.3.8.jar:5.3.8]
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) [spring-context-5.3.8.jar:5.3.8]
at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_201]
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) [spring-context-5.3.8.jar:5.3.8]
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) [spring-context-5.3.8.jar:5.3.8]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.8.jar:5.3.8]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.8.jar:5.3.8]
大概意思就是没有配置服务名,也就是没有配置spring.application.name ,而我们明明是在bootstrap.yml 中添加了的: 而且在启动开始,并没有打印连接到配置中心的日志: 由此猜想,难道是bootstrap.yml 没有被加载?
首先要知道bootstrap.yml 优先于application.yml 加载,其目的是为了在应用启动时,加载一些系统级的资源配置项,比如远程配置中心地址,该文件是由引导上下文 在启动最开始的阶段去加载的。
而该机制是spring-cloud-starter-bootstrap 提供的,Spring Boot 默认是不支持,在Spring Boot 2.4 之后的版本,提供了spring.config.import 通过属性导入配置数据的方法,所以Spring Cloud 也就移除了spring-cloud-starter-bootstrap ,改用spring.config.import 作为默认集成配置中心的方式。官网说明
在Spring Cloud Alibaba 2021.0.1.0 升级指南中,也对此进行了详细说明。
所以怎么解决这个问题呢?
- 方案1:自己引入
spring-cloud-starter-bootstrap - 方案2:使用
spring.config.import 方式引入配置
既然都Spring Cloud 都推荐使用 spring.config.import ,那么我们就用这个吧~
首先删除bootstrap.yml ,在application.yml 使用import 的方式导入Nacos 的配置:
spring:
application:
name: app-service001
cloud:
nacos:
config:
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
config:
import:
- nacos:app-service001.yaml
启动程序,可以看到连接到了Nacos 远程配置中心:
3. 读取远程配置
首先写一个测试配置类,通过@Value 读取配置:
@Configuration
public class Person {
@Value("${person.name}")
String name;
@Value("${person.age}")
Integer age;
在写一个测试访问接口,返回配置内容:
@Autowired
Person person;
@GetMapping("/test")
public String test() {
return person.toString();
}
访问接口,可以看到读取到了Nacos 中的配置: 接着修改以下配置内容,再次访问,发现并没有返回更新后的数据,所以这就牵扯出配置动态刷新的问题。
动态刷新配置
方式1:@RefreshScope
@RefreshScope 是Spring Cloud 提供的注解,可以看到它就是通过Spring 的作用域来实现的。 在之前的配置类上添加注解:
@Configuration
@RefreshScope
public class Person { }
重新启动应用,修改Nacos 中的配置,再通过接口查看数据,可以看到是最新修改后的数据~~
方式2: @NacosValue
@NacosValue 在看到这个注解的时候,去看了源码,上面注释写的是Annotation which extends value to support auto-refresh. ,说它是@Value 注解的扩展,并支持动态刷新。
然后直接在上面的测试案例中使用@NacosValue ,发现连配置中心的配置都获取不到,更不用说动态刷新了。
@NacosValue(value = "${person.name}", autoRefreshed = true)
String name;
接着咨询了一下开发大佬: 又在官网中发现了相关说明: 由上总结:@NacosValue 在Spring Cloud 并不能直接使用,只是为了在纯Spring 环境中方便集成配置中心,Spring Cloud 环境下使用其本身推荐的方式。
要想使用@NacosValue 需要添加以下依赖:
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<version>1.1.1</version>
</dependency>
然后在启动类或者配置类上添加@EnableNacosConfig 和@NacosPropertySource 注解:
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
@NacosPropertySource(dataId = "app-service001.yaml", autoRefreshed = true)
使用@NacosConfigurationProperties 获取配置:
@NacosConfigurationProperties(prefix = "person",
dataId = "app-service001.yaml",
autoRefreshed = true,
type = ConfigType.YAML
)
@Data
@Component
public class NacosValueConfig {
private String name;
private Integer age;
}
或者 @NacosValue 获取配置:
@NacosValue(value = "${person.name}", autoRefreshed = true)
String name;
@GetMapping("/value")
public String value() {
System.out.println(nacosValueConfig.toString());
System.out.println(person.toString());
System.out.println(name);
return "@NacosConfigurationProperties ";
}
启动项目,访问获取配置接口: 修改配置,再次访问,可以看到打印了配置刷新的日志,并且获取到了最新配置: 当然方式2 并不推荐使用
|