【參考】Spring(AbstractRoutingDataSource)實現動態數據源切換--轉載html
【參考】 利用Spring的AbstractRoutingDataSource解決多數據源的問題 java
一:關於具體的原理說明請卡上面的參考連接mysql
二:操做步驟 :在你數據庫配置文件中(個人是spring-dao.xml)配置多數據源 這裏只展現了 數據庫的配置 spring
<!-- 配置整合mybatis--> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath*:jdbc.properties</value> </list> </property> </bean> <!--配置數據庫的鏈接池--> <bean id="abstractDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 配置連接屬性 多數據源配置--> <!-- <property name="driverClass" value="${driver}"/> <property name="jdbcUrl" value="${url}"/> <property name="user" value="${username}"/> <property name="password" value="${password}"/>--> <!--配置c3p0鏈接池的私有屬性--> <property name="maxPoolSize" value="30"/> <property name="minPoolSize" value="10"/> <!--關閉連接後不自動commit--> <property name="autoCommitOnClose" value="false"/> <property name="checkoutTimeout" value="1000"/> <!--獲取鏈接失敗重試次數--> <property name="acquireRetryAttempts" value="2"/> </bean> <!--多數據源配置 parent指向上面的配置數據庫的鏈接池abstractDataSource 這裏配置了兩個數據源--> <bean id="base" parent="abstractDataSource"> <property name="driverClass" value="${driver}"/> <property name="jdbcUrl" value="${url}"/> <property name="user" value="${username}"/> <property name="password" value="${password}"/> </bean> <bean id="server_1" parent="abstractDataSource"> <property name="driverClass" value="${server_1_driver}"/> <property name="jdbcUrl" value="${server_1_url}"/> <property name="user" value="${server_1_username}"/> <property name="password" value="${server_1_password}"/> </bean> <!-- 在RoutingDataSource類中讀取 當前的返回值 並匹配key值 選擇你的數據庫源--> <bean id="dataSource" class="com.cdms.dao.resources.RoutingDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="base" value-ref="base"></entry> <entry key="server_1" value-ref="server_1"></entry> </map> </property> <property name="defaultTargetDataSource" ref="base"></property> </bean> <!-- 配置sqlSessionFactory對象--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入數據庫鏈接池--> <property name="dataSource" ref="dataSource"/> <!-- 配置Mybatisq全局文件:--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <!-- 掃描entity包--> <property name="typeAliasesPackage" value="com.cdms.entity"/> <!-- 掃描sql配置文件--> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean>
另外 個人jdbc:perperties 配置文件是
sql
driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/course_design?useUnicode=true&characterEncoding=UTF-8 username=root password=root server_1_driver=com.mysql.jdbc.Driver server_1_url=jdbc:mysql://127.0.0.1:3306/course_design_test?useUnicode=true&characterEncoding=UTF-8 server_1_username=root server_1_password=root
RoutingDataSource類和DynamicDataSourceHolder類
public class RoutingDataSource extends AbstractRoutingDataSource{ public final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override protected Object determineCurrentLookupKey() { String dataSourceName = DynamicDataSourceHolder.getDataSourceName(); if(dataSourceName == null){ dataSourceName = DataSourceType.BASE.getDataSource(); } logger.info("選擇的數據庫是:"+dataSourceName); return dataSourceName; } }
public class DynamicDataSourceHolder { //解決線程安全問題 private static final ThreadLocal<String> holder = new ThreadLocal<String>(); public static void putDataSourceName(String dataName){ holder.set(dataName); } public static String getDataSourceName(){ return holder.get(); } public static class DataSourceName{ public final static String BASE = "base"; } }
咱們能夠經過在holder中 put數據庫的key值 來實現數據源的動態加載,其中 ThreadLocal<String> holder 保證了線程安全,而 RoutingDataSource
類裏面的determineCurrentLookupKey()方法返回值 就是數據源的key值 配置文件經過這個key值找到了當前的配置源連接。這個是的測試 我就很少演示。 數據庫
那咱們怎麼動態的進行數據連接呢,咱們能夠經過aop切面變成來實現編程
具體的aop切面編程的配置這裏很少作介紹,能夠參考以前的記過博文 有介紹
三:AOP注入實現 數據源的動態配置 首先須要第一一個切點。安全
package com.cdms.aop; import com.cdms.eunms.DataSourceType; import java.lang.annotation.*; /** * 建立 by 草帽boy on 2017/3/29. */ @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ChooseDataSource { /** * 數據庫名稱 默認似base * @return 數據庫名稱 */ String dataSourceName() default "base"; }
而後定義一個切面方法mybatis
package com.cdms.aop; import com.cdms.dao.resources.DynamicDataSourceHolder; import com.cdms.eunms.DataSourceType; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 建立 by 草帽boy on 2017/3/29. */ @Aspect @Component public class GetDataSource { /** * 切面設置要選擇的數據庫 * @param joinPoint * @return * @throws Throwable */ @Around("@annotation(com.cdms.aop.ChooseDataSource)") public Object permission(ProceedingJoinPoint joinPoint) throws Throwable { Object target = joinPoint.getTarget(); Object[] args = joinPoint.getArgs(); Method method = getMethod(joinPoint, args); //獲取數據庫名稱參數 ChooseDataSource chooseDataSource = method.getAnnotation(ChooseDataSource.class); if(chooseDataSource != null){ String dataSourceName = chooseDataSource.dataSourceName(); //堅持名稱是否合法 若是不合法 就用默認數據庫 if(DataSourceType.check(dataSourceName)){ DynamicDataSourceHolder.putDataSourceName(dataSourceName); }else { DynamicDataSourceHolder.putDataSourceName(DataSourceType.BASE.getDataSource()); } } return joinPoint.proceed(); } /** * 獲取切面方法 * @param joinPoint * @param args * @return * @throws NoSuchMethodException */ private Method getMethod(ProceedingJoinPoint joinPoint, Object[] args) throws NoSuchMethodException { // Class[] argsClazz = new Class[args.length]; // for(int i = 0 ; i < args.length; i++){ // argsClazz[i] = args[i].getClass(); // } String methodName = joinPoint.getSignature().getName(); Class clazz = joinPoint.getTarget().getClass(); Method[] methods = clazz.getMethods(); for(Method method : methods) { if (methodName.equals(method.getName())) { return method; } } return null; } }
<!-- 啓動@aspectj的自動代理支持--> <aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy> <!-- 定義aspect類 --> <bean id="logAopAction" class="com.cdms.aop.LogAopAction"></bean> <bean id="aopTest" class="com.cdms.aop.DemoAopTest"></bean> <bean id="getDataSourcesName" class="com.cdms.aop.GetDataSource"></bean>
在以後須要改變數據源的地方 只須要 @ChooseDataSource(dataSourceName = "server_1") 代表你的數據源就看了app
使用單元測試的結果是 ;(@ChooseDataSource(dataSourceName = "server_1") )
(@ChooseDataSource(dataSourceName = "base") )
這個是注入點: