1. 关键类
AbstractRoutingDataSource
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
//多数据源Map lockup key -> DataSource
private Map<Object, Object> targetDataSources;
//默认数据源
private Object defaultTargetDataSource;
private Map<Object, DataSource> resolvedDataSources;
private DataSource resolvedDefaultDataSource;
@Override
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);
}
}
项目启动后,将targetDataSources复制到resolvedDataSources中
//返回当前需要的数据源,由子类实现的方法来提供lockupkey
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;
}
//子类实现获取lockupkey的逻辑
protected abstract Object determineCurrentLookupKey();
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
//在线程T h r
@Override
protected Object determineCurrentLookupKey() {
LOGGER.info("current datasource is : {}", DynamicDataSourceContextHolder.getDataSourceKey());
return DynamicDataSourceContextHolder.getDataSourceKey();
}
}
利用ThreadLocal来存储线程当前的lockupkey
public class DynamicDataSourceContextHolder {
private static ThreadLocal<Object> CONTEXT_HOLDER = ThreadLocal.withInitial(() -> "lookupkey");