Spring動態(tài)監(jiān)聽Nacos配置中心key值變更的實現(xiàn)方法
背景:
Nacos本身提供支持監(jiān)聽配置變更的操作,但在使用起來,個人感覺不是很友好,無法精確到某個key的變更監(jiān)聽
實現(xiàn)方法:
1. 自定義一個只能用在方法上的注解(當然你也可以自定義不僅僅用在方法上)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigListener {
/**
* 待監(jiān)聽的key或key前綴
*/
String key();
}2. 添加具體實現(xiàn)
@Slf4j
@Configuration
public class RefreshEnvironmentConfig implements ApplicationListener<EnvironmentChangeEvent>, EnvironmentAware, BeanPostProcessor {
private Environment environment;
private final Map<String, Map<Method, Object>> listeners = new ConcurrentHashMap<>(64);
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
Map<Method, ConfigListener> annotatedMethods = MethodIntrospector.selectMethods(targetClass, this::findListenerAnnotations);
if (!annotatedMethods.isEmpty()) {
for (Map.Entry<Method, ConfigListener> entry : annotatedMethods.entrySet()) {
listeners.computeIfAbsent(entry.getValue().key(), k -> new HashMap<>()).put(entry.getKey(), bean);
log.info("Register @ConfigListener methods processed on bean {} listener key {}", beanName, entry.getValue().key());
}
}
this.nonAnnotatedClasses.add(bean.getClass());
}
return bean;
}
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
Set<String> keys = event.getKeys();
keys.forEach(key -> {
String value = environment.getProperty(key);
int index = 0;
do {
index = key.indexOf(".", index + 1);
String subKey = index > 0 ? key.substring(0, index) : key;
Map<Method, Object> methodMap = listeners.get(subKey);
if (methodMap != null) {
methodMap.forEach((method, bean) -> {
try {
method.invoke(bean, key, value);
} catch (IllegalAccessException | InvocationTargetException e) {
log.error("Refresh @ConfigListener {}, error {}", bean, e.getMessage(), e);
}
});
}
} while (index > 0);
});
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
private ConfigListener findListenerAnnotations(Method method) {
return findListenerAnnotationsByAnnotatedElement(method);
}
private ConfigListener findListenerAnnotationsByAnnotatedElement(AnnotatedElement element) {
return AnnotationUtils.findAnnotation(element, ConfigListener.class);
}
}3. demo
@ConfigListener(key = "test.value")
public void listener1(String key, String newValue) {
log.info("listener1 listened {}-->{}", key, newValue);
}
@Async
@ConfigListener(key = "test")
public void listener2(String key, String newValue) {
log.info("listener2 listened {}-->{}", key, newValue);
}已上實現(xiàn),不僅僅適用于Nacos,理論上也適用于其他配置中心,(個人僅驗證過Nacos)
拓展:spring監(jiān)聽nacos配置中心文件變化的兩種方式
1.前置條件
1.1依賴
<properties>
<spring-boot.version>2.4.2</spring-boot.version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
spring-cloud-starter-bootstrap需要引入
1.2配置
1.2.1 nocos配置
我們要監(jiān)聽other.yaml文件的other.name|age屬性

1.2.2 bootstrap.yml文件內(nèi)容
server:
port: 8080
---
spring:
application:
#需要指定
name: gateway
profiles:
active: dev
---
spring:
cloud:
nacos:
discovery:
#需要配置
server-addr: 192.168.56.150:8848
group: DEFAULT_GROUP
config:
#需要配置
server-addr: 192.168.56.150:8848
group: DEFAULT_GROUP
file-extension: yaml
extension-configs:
- data-id: gateway-routes.yaml
group: DEFAULT_GROUP
refresh: true
- data-id: other.yaml
group: DEFAULT_GROUP
refresh: true
1.3屬性文件映射
@RefreshScope//Bean 在運行時刷新
@ConfigurationProperties(prefix = "other")//要綁定外部屬性的前綴
@Configuration//設置為bean
public class Config {
//映射other.yaml ->oher.name
private String name;
//映射other.yaml ->oher.age
private String age;
//啟動后定時打印當前bean中的值,不推薦這種方式,做測試方法
@PostConstruct
public void testValueIsChange() {
new Thread(() -> {
int i = 1;
do {
Config bean = SpringBeanUtil.getBean(Config.class);
System.out.println("--- >" + i + "-->當前bean值: " + "name:" + bean.getName() + "|age:" + bean.getAge());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
i++;
} while (true);
}).start();
}
//....get/set方法
}
2監(jiān)聽
2.1第一種方式nacos的SDK
@Component
public class OtherListen {
@Resource//注入NacosConfigManager
public void nacosListen(NacosConfigManager nacosConfigManager) {
//獲取配置中心服務
ConfigService configService = nacosConfigManager.getConfigService();
try {
//對配置中心添加監(jiān)聽(配置文件的dataId,group)
configService.addListener("other.yaml", "DEFAULT_GROUP", new AbstractConfigChangeListener() {
//監(jiān)聽后的處理邏輯
@Override
public void receiveConfigChange(ConfigChangeEvent configChangeEvent) {
for (ConfigChangeItem changeItem : configChangeEvent.getChangeItems()) {
System.out.println("nacos方式監(jiān)聽" + changeItem.getKey() + "-----" + changeItem.getNewValue());
}
}
});
} catch (NacosException e) {
throw new RuntimeException(e);
}
}
//注解監(jiān)聽spring.cloud環(huán)境下需要添加額外依賴,可以參考官方文檔,這里不做演示
@NacosConfigListener(dataId = "other.yaml")
public void onReceived(String value) {
System.out.println("onReceived : " + value);
}
}
2.2第二種方式監(jiān)聽spring的環(huán)境修改
//利用spring事件通知機制
@Component
public class OtherListen implements ApplicationListener<EnvironmentChangeEvent> {
@Resource
private ConfigurableEnvironment environment;
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
for (String key : event.getKeys()) {
System.out.println("spring方式監(jiān)聽: key:" + key + "value:" + environment.getProperty(key));
}
}
}
3.測試
- 啟動后,正常讀取到nacos other.yaml數(shù)據(jù)

- 修改nacos other.yaml數(shù)據(jù)

- 查看監(jiān)聽是否正常
spring監(jiān)聽正常

nacosSDk監(jiān)聽正常

到此這篇關于Spring動態(tài)監(jiān)聽Nacos配置中心key值變更的實現(xiàn)方法的文章就介紹到這了,更多相關Spring動態(tài)監(jiān)聽Nacos key值變更內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot?項目打成?jar后加載外部配置文件的操作方法
這篇文章主要介紹了SpringBoot?項目打成?jar后加載外部配置文件的操作方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
IntelliJ IDEA設置Tabs實現(xiàn)同時打開多個文件且分行顯示
今天小編就為大家分享一篇關于IntelliJ IDEA設置Tabs實現(xiàn)同時打開多個文件且分行顯示,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-10-10
java中Memcached的使用實例(包括與Spring整合)
這篇文章主要介紹了java中Memcached的使用實例(包括與Spring整合),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
Java模擬撲克牌洗牌實現(xiàn)生成52張撲克的方法示例
這篇文章主要介紹了Java模擬撲克牌洗牌實現(xiàn)生成52張撲克的方法,涉及Java數(shù)組遍歷、重排及輸出等相關操作技巧,需要的朋友可以參考下2018-01-01

