在稍微比较庞大的系统中,很有可能涉及分库等多数据源的情况。这时候可能选用一些流程的框架,比如:Sharding-JDBC。但是相比Shardding-JDBC的复杂度,也许实现Spring的抽象类:AbstractRoutingDataSource 更合适和轻便。
该抽象类的定义如下:
/**
* Abstract {@link javax.sql.DataSource} implementation that routes {@link #getConnection()}
* calls to one of various target DataSources based on a lookup key. The latter is usually
* (but not necessarily) determined through some thread-bound transaction context.
*
* @author Juergen Hoeller
* @since 2.0.1
* @see #setTargetDataSources
* @see #setDefaultTargetDataSource
* @see #determineCurrentLookupKey()
*/
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
1:新建立类继承抽象类 AbstractRoutingDataSource。一般情况下只需要实现抽象接口:determineCurrentLookupKey。该方法是获取数据源的KEY,如果该接口返回的类型是自定义对象,切记要重写 equal() 和 hasCode() 方法。
2:使用的时候,一般只需要给2个属性赋值。 一是调用 setTargetDataSources() 方法设置多个数据源。二是调用 setDefaultTargetDataSource() 设置默认的数据源(当使用 determineCurrentLookupKey() 方法得到的key找不到数据源时,将使用默认数据源)
3:AbstractRoutingDataSource 抽象类实例化后,会调用 afterPropertiesSet() 方法。该方法就是解析设置的数据源,代码如下:
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);
}
}
4:该类继承了DataSource 接口。重写了 getConnection 接口。在getConnection 接口中会根据得到的KEY,去指定的数据源获取连接。代码如下:
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}
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;
}