*.properties配置:
<!--数据连接配置一-->
jdbc.type=mysql
jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3066/qshop?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false&allowMultiQueries=true&serverTimezone=GMT%2b8jdbc.username=xxxxxjdbc.password=xxxx<!--数据连接配置二-->
merchant.jdbc.type=mysql
merchant.jdbc.driver=com.mysql.jdbc.Drivermerchant.jdbc.url=jdbc:mysql://localhost:3066/qshop_merchant?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false&allowMultiQueries=true&serverTimezone=GMT%2b8merchant.jdbc.username=xxxxmerchant.jdbc.password=xxxxspring-application.xml配置:
<!-- 数据源一、数据源配置, 使用 druid 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> <property name="driverClassName" value="${jdbc.driver}"/><!-- 基本属性 url、user、password -->
<property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/><!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${jdbc.pool.init}"/> <property name="minIdle" value="${jdbc.pool.minIdle}"/> <property name="maxActive" value="${jdbc.pool.maxActive}"/><!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="60000"/><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/><property name="validationQuery" value="${jdbc.testSql}"/>
<property name="testWhileIdle" value="true"/> <property name="testOnBorrow" value="false"/> <property name="testOnReturn" value="false"/><!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)
<property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> --><!-- 配置监控统计拦截的filters -->
<property name="filters" value="stat"/> </bean> <!-- 数据源二、商家数据源配置, 使用 druid 数据库连接池 --> <bean id="merchantdataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> <property name="driverClassName" value="${merchant.jdbc.driver}"/><!-- 基本属性 url、user、password -->
<property name="url" value="${merchant.jdbc.url}"/> <property name="username" value="${merchant.jdbc.username}"/> <property name="password" value="${merchant.jdbc.password}"/><!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${jdbc.pool.init}"/> <property name="minIdle" value="${jdbc.pool.minIdle}"/> <property name="maxActive" value="${jdbc.pool.maxActive}"/><!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="60000"/><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/><property name="validationQuery" value="${jdbc.testSql}"/>
<property name="testWhileIdle" value="true"/> <property name="testOnBorrow" value="false"/> <property name="testOnReturn" value="false"/><!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)
<property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> --><!-- 配置监控统计拦截的filters -->
<property name="filters" value="stat"/> </bean><!--配置动态数据源-->
<bean id="dynamicDataSource" class="com.yryz.qshop.modules.dynamiclink.DynamicDataSource">
<property name="targetDataSources"> <map key-type="java.lang.String"> <!-- 指定lookupKey和与之对应的数据源 --> <entry key="dataSource" value-ref="dataSource"></entry> <entry key="merchantdataSource" value-ref="merchantdataSource"></entry> </map> </property> <!-- 这里可以指定默认的数据源 {最好不要指定,指定后有坑}--> <!-- <property name="defaultTargetDataSource" ref="dataSource" /> --> </bean>
<bean id="dataSourceAspect" class="com.yryz.qshop.modules.dynamiclink.aspect.DataSourceAspect"/>
<aop:config> <aop:aspect ref="dataSourceAspect"> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.yryz.qshop.modules.merchantremote.service.*.*(..))"/> <aop:before pointcut-ref="dataSourcePointcut" method="intercept" /> </aop:aspect> </aop:config>动态数据源类:
DynamicDataSourceHolder.java
package com.yryz.qshop.modules.dynamiclink;
public class DynamicDataSourceHolder {
/**
* 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰 */ private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();public static String getDataSource() {
return THREAD_DATA_SOURCE.get(); }public static void setDataSource(String dataSource) {
THREAD_DATA_SOURCE.set(dataSource); }public static void clearDataSource() {
THREAD_DATA_SOURCE.remove(); }}DynamicDataSource.java
package com.yryz.qshop.modules.dynamiclink;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() { // 从自定义的位置获取数据源标识 return DynamicDataSourceHolder.getDataSource(); }}
DataSource注解:
package com.yryz.qshop.modules.dynamiclink.inter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)public @interface DataSource { String value();}拦截器
DataSourceAspect.java
package com.yryz.qshop.modules.dynamiclink.aspect;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;import com.yryz.qshop.modules.dynamiclink.DynamicDataSourceHolder;
import com.yryz.qshop.modules.dynamiclink.inter.DataSource;public class DataSourceAspect {
/**
* 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源 * * @param point * @throws Exception */ public void intercept(JoinPoint point) throws Exception { Class<?> target = point.getTarget().getClass(); MethodSignature signature = (MethodSignature) point.getSignature(); // 默认使用目标类型的注解,如果没有则使用其实现接口的注解 for (Class<?> clazz : target.getInterfaces()) { resolveDataSource(clazz, signature.getMethod()); } resolveDataSource(target, signature.getMethod()); }/**
* 提取目标对象方法注解和类型注解中的数据源标识 * * @param clazz * @param method */ private void resolveDataSource(Class<?> clazz, Method method) { try { Class<?>[] types = method.getParameterTypes(); // 默认使用类型注解 if (clazz.isAnnotationPresent(DataSource.class)) { DataSource source = clazz.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } // 方法注解可以覆盖类型注解 Method m = clazz.getMethod(method.getName(), types); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource source = m.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } } catch (Exception e) { System.out.println(clazz + ":" + e.getMessage()); } }}