1.在spring中有一个抽象类AbstractRoutingDataSource类,通过这个类可以实现动态数据源切换。如下是这个类的成员变量
private Map
具体的xml配置如下:
此处的com.xxx.DynamicDataSource是继承了AbstractRoutingDataSource类,具体实现如下:动态数据源切换的实现
2.而AbstractRoutingDataSource实现了InitializingBean接口,并实现了afterPropertiesSet方法。afterPropertiesSet方法是初始化bean的时候执行,可以针对某个具体的bean进行执行。
@Override
public void afterPropertiesSet() {
if (this.targetDataSources == null) {
throw new IllegalArgumentException("Property 'targetDataSources' is required");
}
this.resolvedDataSources = new HashMap (this.targetDataSources.size()); //初始化resolvedDataSources
//循环targetDataSources,并添加到resolvedDataSources中
for (Map.Entry 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属性(map)是存储将要切换的多数据源bean信息。
而如果数据源在数据库中,则需要重写方法determineCurrentLookupKey(),因为数据源bean是动态生成的,然后需要添加到targetDataSources中,此时需要调用afterPropertiesSet()方法,来通知spring有bean更新。
因为此抽象类中都是引用resolvedDataSources属性,所以在此方法中将targetDataSources属性的键值信息存储到resolvedDataSources属性中,以便后续调用。
3.连接数据库的getConnection()方法,调用的是determineTargetDataSource()方法,来创建连接。
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}
而determineTargetDataSource()方法是决定spring容器连接那个数据源
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;
}
而选择哪个数据源又是由determineCurrentLookupKey()方法来决定的,此方法是抽象方法,需要我们继承AbstractRoutingDataSource抽象类来重写此方法。该方法返回一个key,该key是bean中的beanName,并赋值给lookupKey,由此key可以通过resolvedDataSources属性的键来获取对应的DataSource值,从而达到数据源切换的功能。
protected abstract Object determineCurrentLookupKey();
参考地址:
https://blog.csdn.net/u011463444/article/details/72842500
https://blog.csdn.net/u013034378/article/details/81661706