Spring基于aop多数据源切换

笔者之前论述过《 spring 数据源-AbstractRoutingDataSource
基于这个,我们只要保证,每次切换数据源,改变lookupkey就好了,具体思路就是创建一个AbstractRoutingDataSource

的子类,实现抽象方法determineCurrentLookupKey,每次修改数据源,就是让determineCurrentLookupKey返回不同的lookupkey就好了。

aop拦截service服务里头的方法,切换数据源。通常,我们平常都是通过业务来对库表进行分库,那么service就可以根据业务来划分目录,不同目录下的service服务方法,aop拦截切入点,可以根据目录来设定不同的数据源。

下面附上代码:

DynamicDataSource.java(实现determineCurrentLookupKey方法)

package com.wlt.core.common.dynamicdb;

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

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DbContextHolder.getDbType();
    }
}

DBTypeEnum(枚举所有数据源的key)

package com.wlt.core.common.dynamicdb;

public enum DBTypeEnum {
    /**
     * 测试库
     */
    TEST("test");
    private String value;

    DBTypeEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}
DbContextHolder(当前线程数据源持有对象)
package com.wlt.core.common.dynamicdb;

public class DbContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    /**
     * 设置数据源
     * @param dbTypeEnum
     */
    public static void setDbType(DBTypeEnum dbTypeEnum) {
        contextHolder.set(dbTypeEnum.getValue());
    }
    /**
     * 取得当前数据源
     * @return
     */
    public static String getDbType() {
        return contextHolder.get();
    }

    /**
     * 清除上下文数据
     */
    public static void clearDbType() {
        contextHolder.remove();
    }
}

DataSourceInterceptor(基于aop的数据源切换)

package com.wlt.core.common.dynamicdb;

import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DataSourceInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(DataSourceInterceptor.class);

    public void setTest() {
        DbContextHolder.setDbType(DBTypeEnum.TEST);
    }

    public void setDb(JoinPoint jp) {
        String packageName = jp.getTarget().getClass().getPackage().getName();
        if (packageName.contains(".test.")) {
            DbContextHolder.setDbType(DBTypeEnum.TEST);
        }else {
            //设置默认数据源
            DbContextHolder.setDbType(DBTypeEnum.TEST);
        }
        logger.debug("当前数据源:"+DbContextHolder.getDbType());
    }
}

xml配置

maven依赖包配置:

  <properties>
    <druid.version>1.1.8</druid.version>
  </properties>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>${druid.version}</version>
    </dependency>

xml配置:

<?mybatisxml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop.xsd 
	http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
	">
    <!-- 启用CGliB -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

    <!-- 测试库 数据源-->
    <bean name="test" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close">
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="0"/>
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="5"/>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="0"/>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="60000"/>
        <property name="validationQuery" value="SELECT 1 FROM DUAL"/>
        <property name="testOnBorrow" value="false"/>
        <property name="testOnReturn" value="false"/>
        <property name="testWhileIdle" value="true"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="25200000"/>
        <property name="removeAbandoned" value="true"/>
        <property name="removeAbandonedTimeout" value="1800"/>
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="true"/>
        <!-- 监控数据库 -->
        <property name="filters" value="mergeStat"/>
    </bean>

    <bean id="dataSource" class="com.wlt.core.common.dynamicdb.DynamicDataSource">
        <property name="defaultTargetDataSource" ref="test"/>
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <!--key="test",key就是lookupkey-->
                <entry key="test" value-ref="test"/>
                <!--可以配置多个数据源-->
                <!--<entry key="money" value-ref="money"/>-->
            </map>
        </property>
    </bean>

    <!-- Spring整合Mybatis -->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 自动扫描Mapping.xml文件 -->
        <property name="mapperLocations" value="classpath*:mybatisxml/**/*Mapper.xml"/>
        <property name="configLocation" value="classpath:mybatisxml/mybatis-config.xml"/>
        <property name="typeAliasesPackage" value="com.wlt.biz.entity"/>
        <property name="plugins">
            <array>
                <!-- 分页插件配置 -->
                <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor">
                    <!--
                        MYSQL->`mysql`
                        ORACLE->`oracle`
                        DB2->`db2`
                        H2->`h2`
                        HSQL->`hsql`
                        SQLITE->`sqlite`
                        POSTGRE->`postgresql`
                        SQLSERVER2005->`sqlserver2005`
                        SQLSERVER->`sqlserver`
                    -->
                    <property name="dialectType" value="mysql"/>
                </bean>
            </array>
        </property>
        <!-- MP 全局配置注入 -->
        <property name="globalConfig" ref="globalConfig"/>
    </bean>
    <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!--
            AUTO->`0`("数据库ID自增")QW
             INPUT->`1`(用户输入ID")
            ID_WORKER->`2`("全局唯一ID")
            UUID->`3`("全局唯一ID")
        -->
        <property name="idType" value="3"/>
    </bean>
    <!-- MyBatis 动态实现  -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 对Dao 接口动态实现,需要知道接口在哪  -->
        <property name="basePackage" value="com.wlt.biz.mapper"/>
    </bean>

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

    <!-- 启用支持Annotation注解方式的事务管理 -->
    <tx:annotation-driven transaction-manager="transactionManager" order="2"/>

    <!--aop 换源-->
    <bean id="dataSourceInterceptor"
          class="com.wlt.core.common.dynamicdb.DataSourceInterceptor"/>
    <aop:config>
        <aop:aspect  ref="dataSourceInterceptor" order="0">
            <aop:pointcut id="testpoint"
                          expression="execution(* com.wlt.biz.service.test..*.*(..))"/>
            <aop:before method="setTest" pointcut-ref="testpoint"/>
        </aop:aspect>
        <aop:aspect  ref="dataSourceInterceptor" order="0">
            <aop:pointcut id="dbAll" expression="execution(* com.baomidou.mybatisplus.service..*.*(..))"/>
            <aop:before method="setDb" pointcut-ref="dbAll"/>
        </aop:aspect>
    </aop:config>
</beans>

下一篇:spring之jndi数据源配置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独行侠_阿涛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值