詳解AbstractRoutingDataSource(動態資料來源切換)實現原理(轉載)
轉載地址:詳解AbstractRoutingDataSource(動態資料來源切換)實現原理
多資料來源讓人最頭痛的,不是配置多個數據源,而是如何能靈活動態的切換資料來源。例如在一個spring和hibernate的框架的專案中,我們在spring配置中往往是配置一個dataSource來連線資料庫,然後繫結給sessionFactory,在dao層程式碼中再指定sessionFactory來進行資料庫操作。
上圖是單資料來源dataSource結構。但是上圖的缺點太明顯了,不支援多個數據源,於是我們再改進一下,讓它支援多資料來源。
這種結構實現了多資料來源,但是缺點也很明顯啊,具有多個SessionFactory
SessionFactory介面負責初始化Hibernate。它充當資料儲存源的代理,並負責建立Session物件。這裡用到了工廠模式。需要注意的是SessionFactory並不是輕量級的。
顧名思義,SessionFactory,就是用來建立session會話(具體接下來講)的工廠。如果存在多個Sessionfactory 那麼Session是不是就亂套了,因此這種架構不可取。那麼下面這種架構就應用而生。
看看上圖,是不是感覺合理了很多。Spring的AbstractRoutingDataSource
看到這裡你應該就明白了 AbstractRoutingDataSource 的原理。如果你還不明白,沒關係,我們接著往下看。
看看?AbstractRoutingDataSource 的設計原始碼吧!
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
……
}
擴充套件Spring的AbstractRoutingDataSource抽象類(該類充當了DataSource的路由中介, 能有在執行時, 根據某種key值來動態切換到真正的DataSource
從上可以看出它繼承了AbstractDataSource,而AbstractDataSource不就是javax.sql.DataSource的子類嗎,So我們可以分析下它的getConnection方法:
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}
獲取連線的方法中,重點是determineTargetDataSource方法,看原始碼:
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類中的一個抽象方法,而它的返回值是你所要用的資料來源dataSource的key值,有了這個key值,resolvedDataSource(這是個map,由配置檔案中設定好後存入的)就從中取出對應的DataSource,如果找不到,就用配置預設的資料來源。
看完原始碼,應該有點啟發了吧,沒錯!你要擴充套件AbstractRoutingDataSource類,並重寫其中的determineCurrentLookupKey方法,來實現資料來源的切換:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 獲取資料來源(依賴於spring)
* @author linhy
*/
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSource();
}
}