本文最后更新于:2020年5月25日 下午
基于AbstractRoutingDataSource实现动态数据源
实现思路1:
- 维护一个dataSource,里面放置多个数据源
- abstractRoutingDataSource以下简称RoutingDataSource
- RoutingDataSource中getConnection方法被重写,由getDetermineDataSource决定
- 归根结底,由lookUpKey的值,决定获取怎么样的数据源,从而获取连接
- 实现:AOP切面动态的判断规则,修改lookUpKey的值,实现多数据源切换
- 注:事务可能不支持
- 支持分布式事务,需要jta-atomikors
- jta-atomikosDemo地址:https://github.com/zzzyyyzhuyu/jta-atomikos-demo
RouteingDataSource部分源码
package org.springframework.jdbc.datasource.lookup;
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
//存放数据源集合
private Map<Object, Object> targetDataSources;
//存放默认数据源
private Object defaultTargetDataSource;
private boolean lenientFallback = true;
private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
private Map<Object, DataSource> resolvedDataSources;
private DataSource resolvedDefaultDataSource;
//设置数据源列表 (key-value,通过key取value)
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
this.targetDataSources = targetDataSources;
}
//设置默认数据源
public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
this.defaultTargetDataSource = defaultTargetDataSource;
}
/**
* Set the DataSourceLookup implementation to use for resolving data source
* name Strings in the {@link #setTargetDataSources targetDataSources} map.
* <p>Default is a {@link JndiDataSourceLookup}, allowing the JNDI names
* of application server DataSources to be specified directly.
*/
public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
this.dataSourceLookup = (dataSourceLookup != null ? dataSourceLookup : new JndiDataSourceLookup());
}
//数据源初始化之后,初始化相关信息
@Override
public void afterPropertiesSet() {
if (this.targetDataSources == null) {
throw new IllegalArgumentException("Property 'targetDataSources' is required");
}
this.resolvedDataSources = new HashMap<Object, DataSource>(this.targetDataSources.size());
for (Map.Entry<Object, Object> entry : this.targetDataSources.entrySet()) {
Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
this.resolvedDataSources.put(lookupKey, dataSource);
}
if (this.defaultTargetDataSource != null) {
this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);
}
}
//获取连接方法,由determineTargetDataSource方法获取数据源
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
//根据当前的lookedUpKey来获取当前数据源
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(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;
}
//需要重点实现的方法,获取当前lookUpkey
protected abstract Object determineCurrentLookupKey();
实现思路2:
- 自己维护多个DataSource
- 详情可参考
public class DynamicDataSource extends HikariDataSource { @Override public Connection getConnection() throws SQLException { // 获取当前数据源 id Long id = DatasourceConfigContextHolder.getCurrentDatasourceConfig(); // 根据当前id获取数据源 HikariDataSource datasource = DatasourceHolder.INSTANCE.getDatasource(id); if (null == datasource) { datasource = initDatasource(id); } return datasource.getConnection(); } /** * 初始化数据源 * @param id 数据源id * @return 数据源 */ private HikariDataSource initDatasource(Long id) { HikariDataSource dataSource = new HikariDataSource(); // 判断是否是默认数据源 if (DatasourceHolder.DEFAULT_ID.equals(id)) { // 默认数据源根据 application.yml 配置的生成 DataSourceProperties properties = SpringUtil.getBean(DataSourceProperties.class); dataSource.setJdbcUrl(properties.getUrl()); dataSource.setUsername(properties.getUsername()); dataSource.setPassword(properties.getPassword()); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); } else { // 不是默认数据源,通过缓存获取对应id的数据源的配置 DatasourceConfig datasourceConfig = DatasourceConfigCache.INSTANCE.getConfig(id); if (datasourceConfig == null) { throw new RuntimeException("无此数据源"); } dataSource.setJdbcUrl(datasourceConfig.buildJdbcUrl()); dataSource.setUsername(datasourceConfig.getUsername()); dataSource.setPassword(datasourceConfig.getPassword()); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); } // 将创建的数据源添加到数据源管理器中,绑定当前线程 DatasourceHolder.INSTANCE.addDatasource(id, dataSource); return dataSource; } }
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!