AbstractRoutingDataSource抽象类,可以实现动态切换数据库。
抽象方法
重写此方法传入查找查找键 lookupKey
protected abstract Object determineCurrentLookupKey();
成员变量及set方法
- 数据源map,value为DataSource实例或数据源名称String
private Map<Object, Object> targetDataSources;
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
this.targetDataSources = targetDataSources;
}
- 默认数据源,DataSource实例或数据源名称String
@Nullable
private Object defaultTargetDataSource;
public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
this.defaultTargetDataSource = defaultTargetDataSource;
}
- 当指定的lookupKey在targetDataSources中不存在时是否使用默认数据源,默认为ture使用默认数据源
@Nullable
private boolean lenientFallback = true;
public void setLenientFallback(boolean lenientFallback) {
this.lenientFallback = lenientFallback;
}
- 数据源查找,通过提供的数据源名称获取数据源实例
private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
public void setDataSourceLookup(@Nullable DataSourceLookup dataSourceLookup) {
this.dataSourceLookup = (dataSourceLookup != null ? dataSourceLookup : new JndiDataSourceLookup());
}
- 已解析的数据源,value为DataSource实例
@Nullable
private Map<Object, DataSource> resolvedDataSources;
- 已解析的默认数据源
@Nullable
private DataSource resolvedDefaultDataSource;
方法
- 初始化方法,解析数据源
@Override
public void afterPropertiesSet() {
if (this.targetDataSources == null) {
throw new IllegalArgumentException("Property 'targetDataSources' is required");
}
// 解析提供的targetDataSources, 通过resolveSpecifiedDataSource方法将value转换为DataSource类型
this.resolvedDataSources = CollectionUtils.newHashMap(this.targetDataSources.size());
this.targetDataSources.forEach((key, value) -> {
Object lookupKey = resolveSpecifiedLookupKey(key);
DataSource dataSource = resolveSpecifiedDataSource(value);
this.resolvedDataSources.put(lookupKey, dataSource);
});
// 解析默认数据源,转换为DataSource类型
if (this.defaultTargetDataSource != null) {
this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);
}
}
- 解析查找建,默认原样返回
protected Object resolveSpecifiedLookupKey(Object lookupKey) {
return lookupKey;
}
- 将数据源对象解析为数据源实例
protected DataSource resolveSpecifiedDataSource(Object dataSource) throws IllegalArgumentException {
// 可以强转
if (dataSource instanceof DataSource) {
return (DataSource) dataSource;
}
// dataSource为数据源名称,通过dataSourceLookup获取DataSource实例
else if (dataSource instanceof String) {
return this.dataSourceLookup.getDataSource((String) dataSource);
}
else {
throw new IllegalArgumentException(
"Illegal data source value - only [javax.sql.DataSource] and String supported: " + dataSource);
}
}
- 连接数据库方法
// 调用determineTargetDataSource()方法创建连接
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}
- 通过lookupKey获取当前数据源
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
// 未通过lookupKey获取到数据源,符合条件返回默认数据源
if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
dataSource = this.resolvedDefaultDataSource;
}
if (dataSource == null) {
throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
}
return dataSource;
}