使用Apollo動態修改線上數據源


前言

  最近需要實現一個功能,動態刷新線上數據源環境,下面來使用Apollo配置中心和Spring提供的AbstractRoutingDataSource來實現。

具體實現

  Apollo是攜程開源的統一配置中心,和springboot無縫銜接並且不需要安裝其他軟件就可以直接使用,可以實時推送最新的配置文件。Spring提供的AbstractRoutingDataSource用於動態管理數據源,可以動態更新數據源,一般數據庫的讀寫分離也是用這個抽象類實現的。

  對Apollo不熟悉的可以先了解一下,GitHub:https://github.com/ctripcorp/apollo

  關於AbstractRoutingDataSource,介紹一下我們用到的方法

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
    
    //傳入的數據源
    private Map<Object, Object> targetDataSources;

     //拿着子類實現的determineCurrentLookupKey()方法的返回值當做key在這個Map中尋找數據源
    private Map<Object, DataSource> resolvedDataSources;

    //放入多個數據源
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        this.targetDataSources = targetDataSources;
    }

 
    //屬性設置完成后執行
    public void afterPropertiesSet() {
        if (this.targetDataSources == null) {
            throw new IllegalArgumentException("Property 'targetDataSources' is required");
        } else {
            this.resolvedDataSources = new HashMap(this.targetDataSources.size());
            Iterator var1 = this.targetDataSources.entrySet().iterator();

            while(var1.hasNext()) {
                Entry<Object, Object> entry = (Entry)var1.next();
                Object lookupKey = this.resolveSpecifiedLookupKey(entry.getKey());
                DataSource dataSource = this.resolveSpecifiedDataSource(entry.getValue());
                this.resolvedDataSources.put(lookupKey, dataSource);
            }

            if (this.defaultTargetDataSource != null) {
                this.resolvedDefaultDataSource = this.resolveSpecifiedDataSource(this.defaultTargetDataSource);
            }

        }
    }

    protected Object resolveSpecifiedLookupKey(Object lookupKey) {
        return lookupKey;
    }


    //子類要實現的抽象方法,數據源的獲取策略
    protected abstract Object determineCurrentLookupKey();
}

  下面來實現通過Apollo動態修改數據源:

@Configuration
public class DataSourceConfiguration {


    private final static String DATASOURCE_TAG = "db";

    @Autowired
    ApplicationContext context;

    @ApolloConfig
    Config config;

    @Bean("dataSource")
    public DynamicDataSource dynamicDataSource() {
     //使用springboot默認的連接池 DynamicDataSource source = new DynamicDataSource(); //只有一個數據源,傳入的Map的key為db,value為使用的數據源 source.setTargetDataSources(Collections.singletonMap(DATASOURCE_TAG, dataSource())); return source; } //Apollo監聽配置是否修改 @ApolloConfigChangeListener public void onChange(ConfigChangeEvent changeEvent) { SetchangedKeys = changeEvent.changedKeys(); if (changedKeys.contains("spring.datasource.url")) { DynamicDataSource source = context.getBean(DynamicDataSource.class); //當檢測到數據庫地址改變時,重新設置數據源 source.setTargetDataSources(Collections.singletonMap(DATASOURCE_TAG, dataSource())); //調用該方法刷新resolvedDataSources,下次獲取數據源時將獲取到新設置的數據源 source.afterPropertiesSet(); } } public DataSource dataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(config.getProperty("spring.datasource.url", "")); dataSource.setUsername(config.getProperty("spring.datasource.username", "")); dataSource.setPassword(config.getProperty("spring.datasource.password", "")); return dataSource; } //簡單實現AbstractRoutingDataSource,因為只是有一個數據源,所以任何時候選擇的數據源都一樣 class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DATASOURCE_TAG; } } }

  

 

determineCurrentLookupKey


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM