spring+ibatis实现DB的动态切换2(AbstractRoutingDataSource的原理)

转:http://www.360doc.com/content/14/0305/16/16118748_357970326.shtml

最近要为公司多个游戏做类似的统计功能,考虑到模块的复用性,决定做个动态数据源,根据不同的游戏参数切换不同的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
<bean id="onlineDynamicDataSource" class="com.xx.stat.base.dynamic.DynamicDataSource">  
   <property name="targetDataSources">     
      <map key-type="java.lang.String">     
         <entry key="xx" value-ref="dataSourceXX"/>     
         <entry key="yy" value-ref="dataSourceYY"/>     
      </map>     
   </property>     
   <property name="defaultTargetDataSource" ref="dataSource"/>    
</bean>  

观察上面的配置文件,发现我们配置的是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<String> holder = new ThreadLocal<String>();  
      
    public static void putDataSourceName(String name){  
        holder.set(name);  
    }  
      
    public static String getDataSourceName(){  
        return holder.get();  
    }  
}  




你可能感兴趣的:(spring+ibatis实现DB的动态切换2(AbstractRoutingDataSource的原理))