-
Notifications
You must be signed in to change notification settings - Fork 1
原理分析
liuqingyao edited this page Mar 22, 2017
·
9 revisions
Spring JDBC的datasource中有个抽象类:AbstractRoutingDataSource(抽象类)具备动态切换DataSource(接口)的特性 AbstractRoutingDataSource extends AbstractDataSource implements DataSource
AbstractRoutingDataSource的属性
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;AbstractRoutingDataSource的关键方法
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
//下两行代码实现了数据源的切换,而用哪个数据源最终由determineCurrentLookupKey决定(返回了一个key)
Object lookupKey = this.determineCurrentLookupKey();
DataSource 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 + "]");
} else {
return dataSource;
}
}
//留给我们做扩展用的
protected abstract Object determineCurrentLookupKey();MultiDataSource的实现细节
package com.company.component.datasource.multi_datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.util.HashMap;
import java.util.Map;
/**
* User: yaoliuqing
* Time: 14-9-26 下午4:46
*/
public class MultipleDataSource extends AbstractRoutingDataSource {
//保证线程安全
private static final ThreadLocal<String> dataSourceKey = new ThreadLocal<String>();
private static final Map<String, String> packageDataSource = new HashMap<String, String>();
public static void setDataSourceKey(String dataSource) {
dataSourceKey.set(dataSource);
}
public static void usePackageDataSource(String pkgName) {
dataSourceKey.set(packageDataSource.get(pkgName));
}
//实现AbstractRoutingDataSource的determineTargetDataSource
protected Object determineCurrentLookupKey() {
String dsName = dataSourceKey.get();
//阅后即焚
dataSourceKey.remove();
return dsName;
}
public Map<String, String> getPackageDataSource() {
return MultipleDataSource.packageDataSource;
}
public void setPackageDataSource(Map<String, String> packageDataSource) {
MultipleDataSource.packageDataSource.putAll(packageDataSource);
}
}将原来我们在配置中使用的数据源替换成我们自定义的数据源
有了自定义数据源后,我们也要更方便地指定编码中具体某个方法使用哪个数据源(其实不自定义数据源也是可以实现多数据源在同一个项目中使用的,非常麻烦和不灵活以至于我已经记不得怎么用了^_^) 如果通过注解就可以指定某个方法用哪个数据源,岂不方便?!特别是如果你工程正处于数据库拆分,数据库不停加从库的场景下。 于是定义了一个注解
package com.company.component.datasource.multi_datasource.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* User: yaoliuqing
* Time: 14-9-25 下午5:27
* 指定操作的数据库
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD})
public @interface DataSource {
/**
* value dataSource的名称
*/
String value();
}