基於spring實現多資料來源通過註解切換
阿新 • • 發佈:2018-12-11
主要使用spring的AbstractRoutingDataSource實現,先簡單瞭解下AbstractRoutingDataSource
我們配置的多個數據源會放在AbstractRoutingDataSource的 targetDataSources和defaultTargetDataSource中
AbstractRoutingDataSource的getConnection方法會先呼叫determineTargetDataSource()方法返回lookupkey鍵,根據lookupkey鍵對不同目標資料來源呼叫。
所以,我們主要通過自己重寫determineCurrentLookupKey()方法返回lookupKey即可。
實現多資料來源切換的大致思路是:
- 建立用於標誌資料來源的自定義註解
- 通過配置切面,在操作資料庫的方法之前,掃描該方法的註解所配置的資料來源名稱,將名稱儲存在一個代表當前執行緒變數工具類
- 建立AbstarctRoutingDataSource子類,重寫determineCurrentLookupKey()方法,把當前執行緒變數的工具類儲存的資料來源名稱返回即可。
- 在spring配置檔案中,將多個數據源配置到我們建立的DynamicDataSourc
第一步,配置資料來源
<bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="root" /> <property name="password" value="spring" /> <property name="url" value="jdbc:mysql://localhost:3306/taotao?characterEncoding=utf-8" /> <!-- 最大併發連線數 --> <property name="maxActive" value="30" /> <!-- 最小空閒連線數 --> <property name="minIdle" value="5" /> <!-- 用於顯示資料來源監控中的sql語句監控 --> <property name="filters" value="stat" /> </bean> <bean id="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="username" value="root" /> <property name="password" value="spring" /> <property name="url" value="jdbc:mysql://localhost:3306/taobao?characterEncoding=utf-8" /> <!-- 最大併發連線數 --> <property name="maxActive" value="30" /> <!-- 最小空閒連線數 --> <property name="minIdle" value="5" /> <!-- 用於顯示資料來源監控中的sql語句監控 --> <property name="filters" value="stat" /> </bean>
第二步,定義用來切庫的註解,和列舉類
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Dataswitch { Datatype value() default Datatype.master; } public enum Datatype { master("masterDataSource"),slave("slaveDataSource"); private String value; Datatype(String name){ this.value = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
第三步,定義一個當前執行緒的變數的工具類,用於設定對應的資料來源名稱
public class DynamicDataSourceHolder {
private static final ThreadLocal<String> threadLocal = new ThreadLocal<String>();
public static String getThreadLocal() {
return threadLocal.get();
}
public static void setThreadLocal(String name) {
threadLocal.set(name);
}
public static void clear(){
threadLocal.remove();
}
}
第四步,建立AbstactRoutingDataSource的子類,重寫determineCurrentLockupKey方法
public class DynamicDataSource extends AbstractRoutingDataSource{
protected Object determineCurrentLookupKey() {
System.out.println(DynamicDataSourceHolder.getThreadLocal());
return DynamicDataSourceHolder.getThreadLocal();
}
}
第五步,將多資料來源配置到用我們建立的DynamicDataSource
<bean id="dynamicDataSource" class="xin.youhuila.sorceswitch.process.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="masterDataSource" value-ref="masterDataSource"></entry>
<entry key="slaveDataSource" value-ref="slaveDataSource"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="masterDataSource"></property>
</bean>
第六步,配置切面,在操作資料庫方法之前,獲取註解配置的資料來源名稱,返回
@Component
@Aspect
@Order(0)
public class DataSourceAspect {
@Pointcut("execution (* xin.youhuila.sorceswitch.service..*(..))")
public void aspect(){
}
@Before("aspect()")
public void before(JoinPoint joinPoint){
Class<?> clazz = joinPoint.getTarget().getClass();
Method[] method = clazz.getMethods();
Dataswitch dataswitch = null;
boolean is = false;
for(Method m:method){
if(m.isAnnotationPresent(Dataswitch.class)){
dataswitch = m.getAnnotation(Dataswitch.class);
DynamicDataSourceHolder.setThreadLocal(dataswitch.value().getValue());
is = true;
}
}
if(!is){
DynamicDataSourceHolder.setThreadLocal(Datatype.master.getValue());
}
}
@After("aspect()")
public void after(){
DynamicDataSourceHolder.clear();
}
}