Spring Boot 增强之多数据源

前言

Spring Boot本身自带数据源,网上的关于多数据源的分享也多多益善。大体思路一致。本次的分享思路也是如此,不过,我并没有修改(覆盖)原来系统的默认数据源,也就是说。我只做扩展,不做修改。

由于实现RDB持久化的框架众多,比如Mybatis、JPA等等,所有这次我的数据源跟这些框架都没有关系,我只做数据源的增强。

实现目标

  • 不修改(覆盖)Spring Boot自带的数据源
  • 跟持久化框架无关,只跟Spring Boot有关
  • 可以在配置文件里动态配置多个数据源,不限个数
  • 可以在项目里随时添加数据源,比如在项目启动后从数据库里添加多个数据源

实现思路

首先打开Spring Boot源码org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource 可以看到:

@Nullable
private Map<Object, Object> targetDataSources;

// 默认的数据源
@Nullable
private Object defaultTargetDataSource;

private boolean lenientFallback = true;

private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();

// 这里存的就是多个数据源
@Nullable
private Map<Object, DataSource> resolvedDataSources;

@Nullable
private DataSource resolvedDefaultDataSource;

但这些可能不太满足我们的要求,比如这些字段都是private的,我们如果在子类里想用到这些属性,无法使用。于是我们大胆地决定,copy一份出来,我们自己改。如下:

// 默认数据源路由key
protected static final String DEFAULT_DATASOURCE_KEY = "default";

private Map<Object, Object> targetDataSources;

//根据bean名称指定默认数据源,后面会提到为什么会是这个名称
@Resource(name = "defaultDataSource")
private Object defaultTargetDataSource;

private boolean lenientFallback = true;

private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();

//protected 子类可用
protected Map<Object, DataSource> resolvedDataSources;

private DataSource resolvedDefaultDataSource;

同样,我们还是写一个类继承以上copy的类,然后实现抽象接口

@Override
protected Object determineCurrentLookupKey() {
    //线程级切换,判断是哪个source,如果未指定就是默认数据源
    String dataSourceKey = DataSourceContextHolder.getDataSource() == null ? DEFAULT_DATASOURCE_KEY : DataSourceContextHolder.getDataSource();
    logger.trace("Current DataSource is [{}]", dataSourceKey);
    return dataSourceKey;
}

那么如果让默认数据源的beanName变成defaultDataSource,Spring Boot给我们提供的数据源beanNamedataSource。那怎么办呢。我们都知道:Spring加载bean的时候先转成化BeanDefinition,然后再实例化成bean。Spring给我们提供了"接口"让我们重写或自定义bean,哪怕你这个bean未定义,甚至class也不在此项目里,都可以作为一个bean加进来,这里说多了,题外话。言归正传,如果实现,看代码:

private static final String DATASOURCE_BEAN_NAME = "dataSource";

//....

// 此方法就可以重写bean的定义
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    
    //。。。

    //取得已经注册的数据源
    BeanDefinition beanDefinition = registry.getBeanDefinition(DATASOURCE_BEAN_NAME);
    
    //移除并添加为defaultDataSource的数据源
    registry.removeBeanDefinition(DATASOURCE_BEAN_NAME);
    //看,我们这里将默认数据源重新定义成defaultDataSource
    registry.registerBeanDefinition("defaultDataSource", beanDefinition);

    //新建动态数据源,并注册为系统数据源
    GenericBeanDefinition dynamicBeanDefinition = new GenericBeanDefinition();
    dynamicBeanDefinition.setBeanClass(DefaultDynamicDataSource.class);
    dynamicBeanDefinition.setSynthetic(true);
    dynamicBeanDefinition.setPrimary(true);

    //初始化的路由列表
    //设置bean的属性等
    
    //注册给Spring容器
    registry.registerBeanDefinition(DATASOURCE_BEAN_NAME, dynamicBeanDefinition);

}

这些就可以实现了多数据源。下面就是锦上添花的事情了,用aop实现指定数据源,可以在多数据源类里添加一个方法addDatasource就可以动态添加数据源了。这里就不一一详细描述了。代码已开源,文档已提供:

源码: https://github.com/zhouxx/boot-plus/ 模块之boot-plus-core-datasource

文档: https://zhouxx.github.io/boot-plus/#/README

欢迎提出问题一起讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值