1. 程式人生 > >ssm中多資料來源通過Spring aop 實現資料來源的動態切換

ssm中多資料來源通過Spring aop 實現資料來源的動態切換

【具體步驟】
1、編寫動態資料來源相關程式碼。
(1) 編寫DynamicDataSource類。
DynamicDataSource的主要作用是以Map的形式,來儲存多個數據源。
因為該類繼承了父類AbstractRoutingDataSource,在父類中,多資料來源的例項是被存放在一個名為“targetDataSource”的Map型別的成員變數中。

 

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 實現動態切換資料來源
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DatabaseContextHolder.getDbType();
    }
}

 

(2) 編寫DatabaseContextHolder類。

/**
 * create by ××× on 2018/08/27
 */
public class DatabaseContextHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    public static void setDbType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static String getDbType() {
        return contextHolder.get();
    }

    public static void clearDbType() {
        contextHolder.remove();
    }
}


2、編寫切換資料來源的攔截器。

import org.aspectj.lang.JoinPoint;

/**
 * create by ××× on 2018/08/27
 *
 * 資料來源動態切換攔截器
 */
public class DataSourceInterceptor {

    /**
     * 資料來源切換常量
     */
    public static final String MYSQL_DATASOURCE = "mySql";
    public static final String SQLSERVER_DATASOURCE = "sqlServer";

    /**
     * 設定mysql資料來源
     *
     * @param jp
     */
    public void setMysqlDatasource(JoinPoint jp) {
        DatabaseContextHolder.setDbType(MYSQL_DATASOURCE);
    }

    /**
     * 設定資料來源為sqlserver資料庫所對應的資料來源。
     *
     * @param jp
     */
    public void setSqlserverDatasource(JoinPoint jp) {
        DatabaseContextHolder.setDbType(SQLSERVER_DATASOURCE);
    }

}

3、整體的Spring-mybatis.xml配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 配置mysql資料來源 -->
    <bean id="mySqlDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="username" value="${connection.mySql.username}"></property>
        <property name="password" value="${connection.mySql.password}"></property>
        <property name="url" value="${connection.mySql.url}"></property>
        <property name="driverClassName" value="${connection.driverClassName}"></property>
        <property name="maxActive" value="${connection.maxActive}"></property>
        <property name="minIdle" value="${connection.minIdle}"></property>
        <property name="filters" value="${connection.filters}"/>
        <property name="initialSize" value="${connection.initialSize}"/>
        <property name="timeBetweenEvictionRunsMillis" value="${connection.timeBetweenEvictionRunsMillis}"/>
        <property name="minEvictableIdleTimeMillis" value="${connection.minEvictableIdleTimeMillis}"/>
        <property name="maxOpenPreparedStatements" value="${connection.maxOpenPreparedStatements}"/>
        <property name="removeAbandoned" value="${connection.removeAbandoned}"/>
        <property name="removeAbandonedTimeout" value="${connection.removeAbandonedTimeout}"/>
        <property name="logAbandoned" value="${connection.logAbandoned}"/>
    </bean>


    <!-- 配置sqlServer資料來源 -->
    <bean id="sqlServerDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="${connection.sqlServer.driver}"/>
        <property name="url" value="${connection.sqlServer.url}"/>
        <property name="username" value="${connection.sqlServer.username}"/>
        <property name="password" value="${connection.sqlServer.password}"/>
    </bean>

    <!-- aop攔截處理,去掉也能執行對應的 dataSource -->
    <bean id="dataSource" class="qgs.serviceOperation.dataSourceSwitch.DynamicDataSource">
        <property name="defaultTargetDataSource" ref="mySqlDataSource"/> <!--預設主庫-->
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="mySql" value-ref="mySqlDataSource"/>            <!--輔助aop完成自動資料庫切換-->
                <entry key="sqlServer" value-ref="sqlServerDataSource"/>
            </map>
        </property>
    </bean>

    <!-- 配置切換資料來源Key的攔截器 -->
    <bean id="dataSourceInterceptor" class="qgs.serviceOperation.dataSourceSwitch.DataSourceInterceptor"/>

    <!-- myBatis檔案 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations">
            <list>
                <value>classpath:/mapper/mySql/**/*.xml</value>
                <value>classpath:/mapper/sqlServer/*.xml</value>
            </list>
        </property>
        <property name="configLocation">
            <value>classpath:spring/mybatis-setting.xml</value>
        </property>
    </bean>

    <!-- mybatis.spring自動對映 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="qgs.serviceOperation.**.dao,qgs.serviceOperation.sqlServer.customInfo.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <!-- 配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <aop:aspectj-autoproxy expose-proxy="true"/>
    <!-- 註解方式配置事物 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- Spring宣告式事務切面 -->
    <tx:advice id="userTxAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="delete*" propagation="REQUIRED" read-only="false"
                       rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException"/>
            <tx:method name="insert*" propagation="REQUIRED" read-only="false"
                       rollback-for="java.lang.Exception"/>
            <tx:method name="update*" propagation="REQUIRED" read-only="false"
                       rollback-for="java.lang.Exception"/>
            <tx:method name="find*" propagation="SUPPORTS"/>
            <tx:method name="get*" propagation="SUPPORTS"/>
            <tx:method name="select*" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <!-- Spring框架自身提供的切面 -->
        <aop:advisor advice-ref="userTxAdvice" pointcut="execution(public * qgs.serviceOperation.*.service..*.*(..))"
                     order="2"/>

        <!-- 使用者自定義的切面,根據切入點,動態切換資料來源。 -->
        <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor" order="1">
            <aop:before method="setMysqlDatasource" pointcut="execution(* qgs.serviceOperation.*.service..*.*(..))"/>
            <aop:before method="setSqlserverDatasource"
                        pointcut="execution(* qgs.serviceOperation.sqlServer.customInfo.service..*.*(..))"/>
        </aop:aspect>
    </aop:config>
</beans>