最近要为公司多个游戏做类似的统计功能,考虑到模块的复用性,决定做个动态数据源,根据不同的游戏参数切换不同的datasource。
网上查了下,spring2.0以后增加了AbstractRoutingDataSource这个东西。下面是实现方法
首先看下AbstractRoutingDataSource类结构,继承了AbstractDataSource
Java代码
-
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
-
-
}
既然是AbstractDataSource,当然就是javax.sql.DataSource的子类,于是我们自然地回去看它的getConnection方法:
Java代码
-
public Connection getConnection() throws SQLException {
-
return determineTargetDataSource().getConnection();
-
}
原来奥妙就在determineTargetDataSource()里:
Java代码
-
/**
-
* 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
Java代码
-
<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
Java代码
-
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
Java代码
-
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
Java代码
-
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();
-
}
-
}
|