Spring Cloud 配置變化監聽

Spring Cloud 配置變化監聽

背景

開發中遇到個需求,期望可以在配置變更的時候,監聽配置的變化,做一些邏輯處理,原生ApplicationEvent已經有發出對應的配置更新事件,但是包含的是所有的變更,開發人員一般只關心自己需要的配置變更

原生事件發出EnvironmentChangeEvent(如spring cloud config)或RefreshEvent(nacos 最終也會發EnvironmentChangeEvent事件)

對此我們可以基於EnvironmentChangeEvent,最一層包裝,封裝我們自己需要的事件

使用

先看下效果,直接基於EventListener捕獲ConfigRefreshEvent,condition使用el表達式配置需要監聽的key,針對集合或map 可以使用正則匹配

@EventListener(condition = "#event.key eq 'sys.loglevel.root'")
void handleConditionalListener(ConfigRefreshEvent event) {
    // 業務邏輯 balabala
    System.out.println("handleConditionalListener event key :" + event.getKey()
    + ", before :" + event.getBeforeRefresh()
    + ", after :" + event.getAfterRefresh());
}

			/**
     * LIST 或者 MAP 通過正則表達式匹配前綴
     * LIST key爲 sys.loglevel.clazzLevel[0] sys.loglevel.clazzLevel[1] 類似格式
     * MAP key 爲sys.loglevel.clazzLevel.key1 sys.loglevel.clazzLevel.key2 類似格式
     * @param event
     */
    @EventListener(condition = "{#event.key matches '^sys.loglevel.clazzLevel.*'}")
    void clazzLogChangeListener(ConfigRefreshEvent event) {

        log.info("receive log level change event, key :{}, value :{}", event.getKey(), event.getAfterRefresh());
    }

需要的依賴

<dependency>
    <groupId>com.github.yugj</groupId>
    <artifactId>config-refresh-listener-core</artifactId>
    <version>2.0.0</version>
</dependency>

參考代碼:https://github.com/yugj/spring-cloud-config-refresh-listener

實現原理

代碼很簡單直接一個監聽

/**
 * 配置刷新監聽
 * @author yugj
 * @since 1.0-SNAPSHOT
 */
@Service
public class ConfigRefreshListener implements Ordered {

    @Autowired
    private Environment environment;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @EventListener(EnvironmentChangeEvent.class)
    public void listener(EnvironmentChangeEvent event) {
        for (String refreshKey : event.getKeys()) {
        		//查詢刷新配置的值,重新包裝爲自定義的ConfigRefreshEvent
            Object afterRefreshed = environment.getProperty(refreshKey);
            eventPublisher.publishEvent(new ConfigRefreshEvent(this,refreshKey, afterRefreshed, afterRefreshed));
        }
    }

    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE - 1;
    }
}

直接監聽最後的EnvironmentChangeEvent事件(spring cloud各自配置服務刷新最終都會轉換爲該事件),在該事件觸發的時候,包裝爲我們定義的ConfigRefreshEvent,然後依賴spring 事件監聽即可

項目中考慮到代碼簡單通用,沒有獲取變化前的數據

若需要獲取變化之前的數據可以參考org.springframework.cloud.context.refresh.ContextRefresher

public synchronized Set<String> refresh() {
		Set<String> keys = refreshEnvironment();
		this.scope.refreshAll();
		return keys;
	}

	public synchronized Set<String> refreshEnvironment() {
    //刷新之前的值,
		Map<String, Object> before = extract(
				this.context.getEnvironment().getPropertySources());
		addConfigFilesToEnvironment();
    //變化的key值,在上面this.scope.refreshAll();之前可以通過變化的key去查詢before值獲取到變化之前的值
		Set<String> keys = changes(before,
				extract(this.context.getEnvironment().getPropertySources())).keySet();
		this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
		return keys;
	}

擴展使用

類似上面demo可以基於config server做日誌級別的調整及其他需要在進程內維護的數據監聽變更

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章