Spring 實現動態數據源切換--轉載 (AbstractRoutingDataSource)的使用 Spring(AbstractRoutingDataSource)實現動態數據源切換--轉載

【參考】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") )

 

這個是注入點:

相關文章
相關標籤/搜索