Spring Cloud中MyBatis-Plus动态数据源刷新问题

一、问题场景描述

在使用MyBatis-Plus的DynamicRoutingDataSource时遇到的问题,当我在配置中心动态增加或者删除了一个数据源,DynamicDataSourceProperties并没有进行刷新,导致新加的数据源未生效,需要重启服务才能读取到最新的数据源配置

二、问题产生的原因

在Spring Cloud中刷新Bean,官方提供了@RefreshScope注解用于Bean的刷新,然而DynamicDataSourceProperties并没有该注解,导致Spring容器中的Bean一直是工程启动时创建的缓存,那么就无法拿到最新的配置,也就无法通过配置中心去动态增加、删除数据源

三、解决思路

既然官方的DynamicDatasourceProperties没法做到自动刷新,那自己构造一个能刷新的配置不就行了吗?代码如下:

@Data
@RefreshScope
@ConfigurationProperties(DynamicDataSourceProperties.PREFIX)
public class RefreshableDynamicDataSourceProperties implements DisposableBean {

    /**
     * 每一个数据源
     */
    private Map datasource = new LinkedHashMap<>();

    @Override
    public void destroy() throws Exception {
        datasource = new LinkedHashMap<>();
    }
}

注:此处一定要实现DisposableBean接口,并重置数据源,否则在配置中心删除数据源时没法正常删除,这是由于Spring源码中判断Bean的属性如果是复合类型如Map做的操作是putAll()操作,也就是说不会删除原来配置。

上面只是完成了第一步,下面还要将咱们自己的配置在配置刷新的时候加入到DynamicRoutingDataSource中,那么此时需要一个监听器去监听配置刷新的事件,代码如下:

@Order(0)
@Configuration
@RequiredArgsConstructor
@ConditionalOnClass(DynamicDataSourceAutoConfiguration.class)
@EnableConfigurationProperties(RefreshableDynamicDataSourceProperties.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, DynamicDataSourceAutoConfiguration.class})
public class DynamicDataSourceConfig implements ApplicationListener {
    private final RefreshableDynamicDataSourceProperties properties;
    private final DataSource dataSource;
    private final DefaultDataSourceCreator creator;

    @Override
    public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
        //获取最新的数据源
        Map datasource = properties.getDatasource();
        //获取原来的数据源
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        //移除当前数据源中不存在的数据源
        Set keys = datasource.keySet();
        //判断是否存在(不存在即删除)
        ds.getDataSources().entrySet().removeIf(next -> !keys.contains(next.getKey()));
        //添加新的数据源
        datasource.forEach((key, value) -> {
            ds.addDataSource(key, creator.createDataSource(value));
        });
    }
}

此时就实现了不重启工程的情况下动态应用配置中心数据源了。

四、总结

本人也是第一次遇到这种坑,记录一下自己的解决思路和方案,至于官方为什么没有加@RefreshScope实现配置自动刷新这就不得而知了。

你可能感兴趣的:(Spring Cloud中MyBatis-Plus动态数据源刷新问题)