利用AbstractRoutingDataSource实现动态数据源切换

最近要为公司多个游戏做类似的统计功能,考虑到模块的复用性,决定做个动态数据源,根据不同的游戏参数切换不同的datasource。

网上查了下,spring2.0以后增加了AbstractRoutingDataSource这个东西。下面是实现方法

 

首先看下AbstractRoutingDataSource类结构,继承了AbstractDataSource

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {

}
 

既然是AbstractDataSource,当然就是javax.sql.DataSource的子类,于是我们自然地回去看它的getConnection方法:

	public Connection getConnection() throws SQLException {
		return determineTargetDataSource().getConnection();
	}

 原来奥妙就在determineTargetDataSource()里:

	/**
	 * Retrieve the current target DataSource. Determines the
	 * {@link #determineCurrentLookupKey() current lookup key}, performs
	 * a lookup in the {@link #setTargetDataSources targetDataSources} map,
	 * falls back to the specified
	 * {@link #setDefaultTargetDataSource default target DataSource} if necessary.
	 * @see #determineCurrentLookupKey()
	 */
	protected DataSource determineTargetDataSource() {
		Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
		Object lookupKey = determineCurrentLookupKey();
		DataSource dataSource = (DataSource) this.resolvedDataSources.get(lookupKey);
		if (dataSource == null) {
			dataSource = this.resolvedDefaultDataSource;
		}
		if (dataSource == null) {
			throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
		}
		return dataSource;
	}

这里用到了我们需要进行实现的抽象方法determineCurrentLookupKey(),该方法返回需要使用的DataSource的key值,然后根据这个key从resolvedDataSources这个map里取出对应的DataSource,如果找不到,则用默认的resolvedDefaultDataSource

 

    
          
             
                
                
             
          
         
    
 

观察上面的配置文件,发现我们配置的是targetDataSources和defaultTargetDataSource

 

	public void afterPropertiesSet() {
		if (this.targetDataSources == null) {
			throw new IllegalArgumentException("targetDataSources is required");
		}
		this.resolvedDataSources = new HashMap(this.targetDataSources.size());
		for (Iterator it = this.targetDataSources.entrySet().iterator(); it.hasNext();) {
			Map.Entry entry = (Map.Entry) it.next();
			Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
			DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
			this.resolvedDataSources.put(lookupKey, dataSource);
		}
		if (this.defaultTargetDataSource != null) {
			this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);
		}
	}

 

下面就是我们自己实现的子类DynamicDataSource

public class DynamicDataSource extends AbstractRoutingDataSource{
    
    @Override
    public void setTargetDataSources(Map targetDataSources) {
        super.setTargetDataSources(targetDataSources);
    }
    
    @Override
    public Object unwrap(Class iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return false;
    }

    @Override
    protected Object determineCurrentLookupKey() {
        String dataSourceName = DynamicDataSourceHolder.getDataSourceName();
        return dataSourceName;
    }

 

DynamicDataSourceHolder

public class DynamicDataSourceHolder {

    private static final ThreadLocal holder = new ThreadLocal();
    
    public static void putDataSourceName(String name){
        holder.set(name);
    }
    
    public static String getDataSourceName(){
        return holder.get();
    }
}
 

 

 

 

你可能感兴趣的:(spring)