1. 程式人生 > >解析配置檔案自動裝配 DataSource + AbstractRoutingDataSource + AOP 實現動態資料來源 下:配置動態資料來源,AOP 進行使用

解析配置檔案自動裝配 DataSource + AbstractRoutingDataSource + AOP 實現動態資料來源 下:配置動態資料來源,AOP 進行使用

上篇文章中已經藉助 DynamicDataSourceBuilder 類從配置檔案中解析得到了預設資料來源和動態資料來源,接下來需要配置動態資料來源的“本體”,並藉助 AOP 動態的切換資料來源。

配置動態資料來源

AbstractRoutingDataSource 實現了 InitializingBean 介面,在 afterPropertiesSet方法中通過處理 targetDataSourcesdefaultTargetDataSource中得到最終的 resolvedDefaultDataSourceresolvedDataSources,我們的實現類(動態資料來源“本體”)需要覆寫該方法,從而給targetDataSources

defaultTargetDataSource進行賦值。
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,可以在 這裡 找到