• AbstractRoutingDataSource+AOP+JNDI实现spring动态数据源


    参考:https://www.cnblogs.com/wyb628/p/7240061.html

    • 背景:

    系统已有数据源1(主要数据源),数据源2(只有一个目录的xml使用该数据源),由于这2个数据源分别扫描不同的包,相互不打扰,所以一直用的好好的。

    直到,需要新增一个数据源3,跟数据源2用法一模一样的,但是需要在程序中具体用到的时候才能决定具体使用哪一个。所以,基于此,针对数据源2和3实现了动态数据源。

    • 思路:
    1. sessionFactory的dataSource属性设置成能从代码中动态读取,继承类:org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
    2. 使用ThreadLocal为每一个线程单独设置数据源的key,该key可以匹配到配置文件中的jndi。
    3. 通过aop进行动态的设置key,使用完毕remove,防止出现内存泄露。
    • 代码如下:

    spring-mybatis.xml配置数据源1和动态数据源2/3如下:<?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" xmlns:jee="http://www.springframework.org/schema/jee"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/jee 
        http://www.springframework.org/schema/jee/spring-jee-4.3.xsd">
    
        <!-- data source 1-->
        <jee:jndi-lookup id="dataSource" lookup-on-startup="false"
            proxy-interface="javax.sql.DataSource" jndi-name="${first.jndi.database}" />
            
        <!--  data source 2-->
        <jee:jndi-lookup id="secondDataSource"
            lookup-on-startup="false" proxy-interface="javax.sql.DataSource"
            jndi-name="${second.jndi.database}" />
        <!-- data source 3-->
        <jee:jndi-lookup id="thirdDataSource"
        lookup-on-startup="false" proxy-interface="javax.sql.DataSource"
        jndi-name="${third.jndi.database}"/>
            
        <bean id="PaginationInterceptor" class="XXXX.mybatis.plugins.PaginationInterceptor"/>
        
        <!-- 数据源1的配置 -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
            <property name="mapperLocations">
            <array>
                <value>classpath:XXXXX/database/*/impl/*.xml</value>
                <value>classpath*:XXXX/client/dao/**/*Mapper.xml</value>
                <value>classpath*:XXXXX/restructure/**/*Mapper.xml</value>
            </array>
            </property>
            <property name="plugins">
                <array>
                    <ref bean="PaginationInterceptor" />
                    <ref bean="myInterceptor"/>
                </array>
            </property>
        </bean>
    
        <bean id="myInterceptor" class="XXXXX.mybatis.MyInterceptor"></bean>
    
    
    
        <!--配置数据源1的扫描路径-->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="XXXX.data.database" />
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        </bean>
    
        <!-- 配置事务管理器 -->
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
    
        <!-- 注解方式配置事务 -->
        <tx:annotation-driven transaction-manager="transactionManager" />
    
        <!-- 动态数据源的配置-->
        <bean id="myDynamicDataSource" class="XXXX.DynamicDataSource">
        <property name="targetDataSources">
        <map key-type="java.lang.String">
        <!--注意这里key跟代码中对应即可 value要跟配置的jndi对应-->
        <entry value-ref="secondDataSource" key="mySecond"/>
        <entry value-ref="thirdDataSource" key="myThree"/>
        </map>
        </property>
        <!--配置默认的--->
        <property name="defaultTargetDataSource" ref="secondDataSource"/>
        </bean>
    
        <bean id="mySqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="myDynamicDataSource" />
            <!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
            <property name="mapperLocations"
                value="classpath:YYYYY/*/impl/*.xml" />
        </bean>
    
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="YYYYYXXXX.YYYdatabase" />
            <property name="sqlSessionFactoryBeanName" value="mySqlSessionFactory" />
        </bean>
    
        <!-- 配置事务管理器 -->
        <bean id="transactionManager_my"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="myDynamicDataSource" /> 
    </bean>
    </beans>

    其中:<bean id="myDynamicDataSource" class="XXXX.DynamicDataSource">

    DynamicDataSource.java内容如下:

    package XXXX;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DataSourceContextHolder.getSourceType();
        }
    }
    DataSourceContextHolder.java内容如下:
    
    

    package XXXX;

    
    

    public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextDynamicSourceHolder = new ThreadLocal<String>();

    
    

    public static void setDataSourceType(String sourceType) {
    contextDynamicSourceHolder.set(sourceType);
    }

    
    

    public static String getSourceType() {
    return contextDynamicSourceHolder.get();
    }

    
    

    public static void clearSourceType() {
    contextDynamicSourceHolder.remove();
    }
    }

     

    使用AOP对需要使用动态数据源的地方进行设置值,aop如下:

    package XXXX;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class contextDynamicSourceHolder {
        private   final Logger LOG=LoggerFactory.getLogger(contextDynamicSourceHolder.class);
        
        //切点设置为需要使用动态数据源的地方
        @Pointcut("execution(* XXXX.ZZZZMapper.*(..))")
        public void pointCut() {
    
        }
    
        @Before("pointCut()")
        public void before(JoinPoint jp) {
            Object[] args=jp.getArgs();
            Signature signature = jp.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            String[] argNames = methodSignature.getParameterNames();
            //省略判断条件,根据判断条件设置数据源的key
            DataSourceContextHolder.setDataSourceType(XXX);
        }
    
        @AfterReturning("pointCut()")
        public void afterReturnning() {
            DataSourceContextHolder.clearSourceType();
        }
    
        @AfterThrowing("pointCut()")
        public void afterThrowing() {
            DataSourceContextHolder.clearSourceType();
        }
    }
     如果aop没有生效,
    1.检查一下spring.xml配置文件中是否有:<aop:aspectj-autoproxy/>
    2.检查切点表达式是否正确
    比如:execution(* XXX.UUUMapper.*(..))

         XXX是路径  UUUMapper是具体的文件名称  .* 表示所有的方法 ()表示参数

  • 相关阅读:
    【class2src】Decompiler
    【JAVA-JDT-AST】Java抽象语法树的构建、遍历及转成dot格式(附Github源码)
    【IBM-WALA】Step by Step : use WALA to generate System Dependency Graph PDF and Dot File (Mac)
    [R]统计工具包
    [PYTHON-TSNE]可视化Word Vector
    【Latex】常用工具包
    [Python]编程之美
    【python】用python生成pdf文件
    【python】并查集
    【Scikit】实现Multi-label text classification代码模板
  • 原文地址:https://www.cnblogs.com/LittleSix/p/10816497.html
Copyright © 2020-2023  润新知