美文网首页
解析配置文件自动装配 DataSource + Abstract

解析配置文件自动装配 DataSource + Abstract

作者: DJN_ | 来源:发表于2018-11-13 17:07 被阅读0次

上篇文章中已经借助 DynamicDataSourceBuilder 类从配置文件中解析得到了默认数据源和动态数据源,接下来需要配置动态数据源的“本体”,并借助 AOP 动态的切换数据源。

配置动态数据源

AbstractRoutingDataSource 实现了 InitializingBean 接口,在 afterPropertiesSet方法中通过处理 targetDataSourcesdefaultTargetDataSource中得到最终的 resolvedDefaultDataSourceresolvedDataSources,我们的实现类(动态数据源“本体”)需要覆写该方法,从而给targetDataSourcesdefaultTargetDataSource进行赋值。

image.png
可以看到第 118 行如果 targetDataSources 为 null 就会抛出异常,因此我们的导出类需要先进行赋值,再调用父类方法,动态数据源配置代码如下:
@Component
public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal<DsKey> dataSourceKey = new InheritableThreadLocal<DsKey>() {
        @Override
        protected DsKey initialValue() {
            return DsKey.DATASOURCE;
        }
    };
    @Autowired
    private DynamicDataSourceBuilder dynamicDataSourceBuilder;

    // 维护数据源 key(Lookup key)
    private static Set<String> dsKeySet = new HashSet<>();

    public static DsKey getDataSourceKey() {
        return dataSourceKey.get();
    }
    public static void setDataSourceKey(DsKey key) {
        dataSourceKey.set(key);
    }

    static int addDsKey(String key) {
        dsKeySet.add(key);
        return dsKeySet.size();
    }
    public static void clearDataSourceType() {
        dataSourceKey.remove();
    }
    public static boolean contains(String key) {
        return dsKeySet.contains(key);
    }
    public static boolean contains(DsKey key) {
        return dsKeySet.contains(key.getCode());
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return dataSourceKey.get();
    }

    @Override
    public void afterPropertiesSet() {

        // 所有数据源,包括默认数据源
        Map<String, DataSource> customDataSources = dynamicDataSourceBuilder.getTargetDataSources();

        // Lookup key
        customDataSources.forEach((key, da) -> addDsKey(key));

        // DataSource
        DataSource defaultDataSource = dynamicDataSourceBuilder.getDefaultDataSource();
        setDefaultTargetDataSource(defaultDataSource);
        setTargetDataSources(new HashMap<>(customDataSources));

        super.afterPropertiesSet();
    }
}

  • DsKey 是个枚举类型,维护了所有的 ds-keys,ThreadLocal 类型变量 dataSourceKey 用于维护当前线程所使用的数据源,覆写 ThreadLocal 的 initialValue 方法以指定默认数据源。
  • dsKeySet 集合中维护了所有的 Lookup key,可提供 contains 校验,覆写 afterPropertiesSet 方法时为其赋值。
  • afterPropertiesSet 方法从 DynamicDataSourceBuilder 中得到所有解析到的数据源,并将其赋值给targetDataSourcesdefaultTargetDataSource
  • determineCurrentLookupKey 方法是 AbstractRoutingDataSource 抽象类唯一需要导出类实现的方法,也正是该方法决定当前所用的数据源,而当前的数据源信息维护在 dataSourceKey,当我们需要修改当前数据源时只需要修改dataSourceKey的值即可(通过调用 setDataSourceKey 方法)。

AOP 的方式进行动态切换

定义注解供 AOP 进行拦截,以切换数据源:


image.png

在使用了 DataSource 注解的地方进行数据源切换,方法调用结束时恢复默认数据源:

image.png
在具体业务中如果需要更细粒度的控制数据源,也可直接调用 DynamicDataSource.setDataSourceKey 方法设置数据源,同时在结束操作时需要调用 DynamicDataSource.clearDataSourceType 方法恢复默认数据源。

使用示例

public class TestService {


    @DataSource(dsKey = DsKey.DB1)
    public void test() {
        //
    }

    @DataSource(dsKey = DsKey.DB1)
    public void test1() {
        DynamicDataSource.setDataSourceKey(DsKey.DATASOURCE);
        // do somthing
        DynamicDataSource.setDataSourceKey(DsKey.DB1);
    }


}

代码已上传 GitHub,可以在 这里 找到

相关文章

网友评论

      本文标题:解析配置文件自动装配 DataSource + Abstract

      本文链接:https://www.haomeiwen.com/subject/qdylfqtx.html