Springboot Mybatis配置多数据源

邓尼茨我今天去赶集 2020年03月12日 959次浏览

通过注解的方式实现,可基于类也可以基于方法。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface DataSource{
    String value();
}
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

public class DataSourceAspect {
    private static Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);
    /**
     * 在dao层方法获取datasource对象之前,在切面中指定当前线程数据源
     */
    public void before(JoinPoint point) {

        Object target = point.getTarget();
        String method = point.getSignature().getName();
        Class<?> clazz = target.getClass();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        try {
            Method methodClz = clazz.getMethod(method, parameterTypes);
            Method methodFace = interfaces[0].getMethod(method, parameterTypes);

            Class<?> interfeis = interfaces[0];

            String dataSourceKey="default";

            if (methodClz != null && methodClz.isAnnotationPresent(DataSource.class)) {
                dataSourceKey=methodClz.getAnnotation(DataSource.class).value();
            }else if (methodFace != null && methodFace.isAnnotationPresent(DataSource.class)) {
                dataSourceKey=methodFace.getAnnotation(DataSource.class).value();
            }else if(interfeis.isAnnotationPresent(DataSource.class)){
                dataSourceKey = interfeis.getAnnotation(DataSource.class).value();
            }else if(clazz.isAnnotationPresent(DataSource.class)) {
                dataSourceKey=clazz.getAnnotation(DataSource.class).value();
            }

            DataSourceHolder.putDataSourceKey(dataSourceKey);
            logger.warn("Using database source: "+dataSourceKey);

        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }
}
public class DataSourceHolder {
    public static final ThreadLocal<String> holder = new ThreadLocal<>();

    /**
     * 绑定当前线程数据源
     *
     * @param dataSource
     */
    public static void putDataSourceKey(String dataSource) {
        holder.set(dataSource);
    }

    /**
     * 获取当前线程的数据源
     *
     * @return
     */
    public static String getDataSourceKey() {
        return holder.get();
    }

    /**
     * 删除当前线程的数据源
     *
     * @return
     */
    public static void clearDataSourceKey() {
        holder.remove();
    }

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

public class DynamicDataSource extends AbstractRoutingDataSource{
    /**
     * 获取与数据源相关的key 此key是Map<String,DataSource> resolvedDataSources 中与数据源绑定的key值
     * 在通过determineTargetDataSource获取目标数据源时使用
     */
    @Override
    protected Object determineCurrentLookupKey(){
        return DataSourceHolder.getDataSourceKey();
    }

}
<?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: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"
       default-lazy-init="true">


    <beans profile="dev,sit,uat,production">
        <!-- 多数据源配置-->
        <bean id="firstDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" primary="true">
            <property name="driverClassName" value="${datasource.jdbcDriverClass.1}" />
            <property name="url" value="${datasource.url.1}" />
            <property name="username" value="${datasource.user.1}" />
            <property name="password" value="${datasource.password.1}" />
            <property name="maxActive" value="${datasource.maxActive.1}" />
            <property name="maxIdle" value="${datasource.maxIdle.1}" />
            <property name="minIdle" value="${datasource.minIdle.1}" />
            <property name="maxWait" value="${datasource.maxWaitMillis.1}" />
            <property name="removeAbandoned" value="${datasource.removeAbandoned.1}" />
            <property name="removeAbandonedTimeout" value="${datasource.removeAbandonedTimeout.1}" />
            <property name="testWhileIdle" value="true" />
            <property name="validationQuery" value="select 1" />
            <property name="validationQueryTimeout" value="20" />
            <property name="timeBetweenEvictionRunsMillis" value="${datasource.timeBetweenEvictionRunsMillis.1}" />
            <property name="connectionProperties">
                <value>clientEncoding=utf-8</value>
            </property>
        </bean>

        <bean id="sencondDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" primary="true">
            <property name="driverClassName" value="${datasource.jdbcDriverClass.2}" />
            <property name="url" value="${datasource.url.2}" />
            <property name="username" value="${datasource.user.2}" />
            <property name="password" value="${datasource.password.2}" />
            <property name="maxActive" value="${datasource.maxActive.2}" />
            <property name="maxIdle" value="${datasource.maxIdle.2}" />
            <property name="minIdle" value="${datasource.minIdle.21}" />
            <property name="maxWait" value="${datasource.maxWaitMillis.2}" />
            <property name="removeAbandoned" value="${datasource.removeAbandoned.2}" />
            <property name="removeAbandonedTimeout" value="${datasource.removeAbandonedTimeout.2}" />
            <property name="testWhileIdle" value="true" />
            <property name="validationQuery" value="select 1" />
            <property name="validationQueryTimeout" value="20" />
            <property name="timeBetweenEvictionRunsMillis" value="${datasource.timeBetweenEvictionRunsMillis.2}" />
            <property name="connectionProperties">
                <value>clientEncoding=utf-8</value>
            </property>
        </bean>

        <bean id="mainDataSource" class="fis.starcloud.common.datasource.DynamicDataSource">
            <property name="targetDataSources">
                <map key-type="java.lang.String">
                    <entry key="FIRST" value-ref="firstDataSource"/>
                    <entry key="SECOND" value-ref="secondDataSource"/>
                </map>
            </property>
            <!-- 默认目标数据源为你主库数据源  -->
            <property name="defaultTargetDataSource" ref="firstDataSource"/>
        </bean>


        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="mainDataSource"/>
        </bean>

        <beans>
            <bean id="dataSourceAspect" class="fis.starcloud.common.datasource.DataSourceAspect" />
            <aop:config proxy-target-class="true">
                <aop:aspect id="dataSourceAspect" ref="dataSourceAspect" order="1">
                    <aop:pointcut id="tx" expression="(execution(* fis.starcloud.apicenter.manager..*.*(..))) "/>
                    <aop:before pointcut-ref="tx" method="before" />
                </aop:aspect>
            </aop:config>
        </beans>

    </beans>


    <!-- transaction manager, use JtaTransactionManager for global tx -->
    <beans>
        <tx:annotation-driven transaction-manager="txManager" proxy-target-class="false"/>
        <alias name="txManager" alias="transactionManager"/>
       
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="configuration">
                <bean class="org.apache.ibatis.session.Configuration">
                    <property name="useActualParamName" value="false"/>
                </bean>
            </property>
            <property name="dataSource" ref="mainDataSource"/>
         
            <property name="mapperLocations" value="classpath*:fis/starcloud/apicenter/dao/*Dao.xml"/>
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
            <property name="basePackage" value="fis.starcloud.apicenter.dao"/>
        </bean>

    </beans>

</beans>

在Springboot启动类上加上
@SpringBootApplication(exclude =
)

全部完成!