使用Apollo动态修改线上数据源

本文介绍如何利用Apollo配置中心与Spring的AbstractRoutingDataSource结合,实现实时更新线上数据源,适用于读写分离场景。通过监听Apollo配置变化,自动调整Spring数据源配置,提升应用灵活性。
摘要由CSDN通过智能技术生成

前言

  最近需要实现一个功能,动态刷新线上数据源环境,下面来使用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
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceConfiguration {
 
 
    private final static String DATASOURCE_TAG = "db";
 
    @Autowired
    ApplicationContext context;
 
    @ApolloConfig
    Config config;
 
    @Bean("dataSource")
    public DynamicDataSource dynamicDataSource() {<br>     //使用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; }
    }
}   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值