(#)背景:由於業務的需求,導致需要隨時切換15個數據源,此時不能low逼的去寫十幾個mapper,所以想到了實現一個數據源的動態切換
首先要想重寫多數據源,那么你應該理解數據源的一個概念是什么,DataSourceTransactionManager這個類就是spring中對於數據源的封裝,其中DataSource做為
他的一個成員.接下來我們要介紹一下我們切換動態數據源需要使用的類,AbstractRoutingDataSource,先來看看這個類的源碼
首先看看這幾個變量,targetDataSources代表的就是備選的數據源了,用一個map存儲,顯然是為了在關鍵的時候快速的查找這些數據源,defaultTargetDataSource
就是我們在配置的時候一般都會制定一個默認的數據源就是它了,
程序運行的時候在加載配置文件的時候,首先會執行setTargetDataSources方法,這個方法會加載配置文件中配置的數據源,存儲在上面說的targetDataSource中,
然后是設置setDefaultTergetDataSource,這個就是上面說的默認的數據源,
接下來會執行這個方法,在其中會將所有的數據源用來初始化resolvedDataSources,而當實際上和數據庫產生交互的時候那么會調用到下面的方法:
如果看到這里大概你也知道怎么回事了,在我們實際和數據庫產生交互的時候那么就需要使用到數據源了,那么這個時候我們只是需要重寫這determineCurrentLookupKey
方法,而用這個方法具體干了什么呢?就是用它來尋找數據源啊,也就是說我們在mapper中的配置:
(#)下面看看代碼上怎么來寫
首先為了線程安全我們使用一個ThreadLocal來做存儲
public class ContextHolder { public static final String DATASOURCE_1="dataSource"; public static final String DATASOURCE_2="dataSource2"; private static final ThreadLocal<String> context = new ThreadLocal<String>(); public static void setConsumerType(String consumerType){ context.set(consumerType); } public static String getConsumerType(){ return context.get(); } public static void clearConsumerType(){ context.remove(); } }
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return ContextHolder.getConsumerType(); } }
其實剩下的怎么實現已經很簡單了,基本思路就是使用一個動態代理,在執行這個方法的時候,我們動態的給ContextHoler設置值,我建議使用spring aop,或者如果
不是spring的項目,那么直接只用動態代理也是很好的我覺,下面貼出一些我的簡陋的代碼
@Aspect @Component public class DataSourceAspect { @Pointcut("execution(* com.wang.route.DynamicPersonService.*(..))") public void pointCut() { } @Before(value = "pointCut()") public void before(JoinPoint joinPoint) { ContextHolder.setConsumerTyp(“”); } }