前言
在现在开发的过程中应该大多数朋友都有遇到过切换数据源的需求。比如现在常用的数据库读写分离,或者就是有两个数据库的情况,这些都需要用到切换数据源。
手动切换数据源
使用Spring
的AbstractRoutingDataSource
类来进行拓展多数据源。
该类就相当于一个dataSource
的路由,用于根据key
值来进行切换对应的dataSource
。
下面简单来看下AbstractRoutingDataSource
类的几段关键源码:
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}
/**
* 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 = 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;
}
/**
* Determine the current lookup key. This will typically be
* implemented to check a thread-bound transaction context.
* <p>Allows for arbitrary keys. The returned key needs
* to match the stored lookup key type, as resolved by the
* {@link #resolveSpecifiedLookupKey} method.
*/
protected abstract Object determineCurrentLookupKey();
可以看到其中获取链接的方法getConnection()
调用的determineTargetDataSource
则是关键方法。该方法用于返回我们使用的数据源。
其中呢又是determineCurrentLookupKey()
方法来返回当前数据源的key
值。
之后通过该key值在resolvedDataSources
这个map中找到对应的value
(该value就是数据源)。
resolvedDataSources
这个map则是在:
@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
这个map来进行赋值的。targetDataSources
则是我们在配置文件中进行赋值的,下面会讲到。
再来看看determineCurrentLookupKey()
方法,从protected
来修饰就可以看出是需要我们来进行重写的。
DynamicDataSource 和 DataSourceHolder
于是我新增了DynamicDataSource
类,代码如下:
package com.crossoverJie.util;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* Function:
*
* @author chenjiec
* Date: 2017/1/2 上午12:22
* @since JDK