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