解析配置檔案自動裝配 DataSource + AbstractRoutingDataSource + AOP 實現動態資料來源 下:配置動態資料來源,AOP 進行使用
阿新 • • 發佈:2018-11-16
上篇文章中已經藉助 DynamicDataSourceBuilder
類從配置檔案中解析得到了預設資料來源和動態資料來源,接下來需要配置動態資料來源的“本體”,並藉助 AOP 動態的切換資料來源。
配置動態資料來源
AbstractRoutingDataSource
實現了 InitializingBean
介面,在 afterPropertiesSet
方法中通過處理 targetDataSources
和 defaultTargetDataSource
中得到最終的 resolvedDefaultDataSource
和 resolvedDataSources
,我們的實現類(動態資料來源“本體”)需要覆寫該方法,從而給targetDataSources
defaultTargetDataSource
進行賦值。可以看到第 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
中得到所有解析到的資料來源,並將其賦值給targetDataSources
和defaultTargetDataSource
。determineCurrentLookupKey
方法是AbstractRoutingDataSource
抽象類唯一需要匯出類實現的方法,也正是該方法決定當前所用的資料來源,而當前的資料來源資訊維護在dataSourceKey
,當我們需要修改當前資料來源時只需要修改dataSourceKey
的值即可(通過呼叫setDataSourceKey
方法)。
AOP 的方式進行動態切換
定義註解供 AOP 進行攔截,以切換資料來源:
在使用了 DataSource 註解的地方進行資料來源切換,方法呼叫結束時恢復預設資料來源:
在具體業務中如果需要更細粒度的控制資料來源,也可直接呼叫 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,可以在 這裡 找到