通过注解的方式实现,可基于类也可以基于方法。
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 = )
全部完成!