1、继承AbstractRoutingDataSource类,实现determineCurrentLookupKey方法
spring确定数据源时,会优先调用determineCurrentLookupKey方法,可实现此方法,自定义选择的数据源,值为spring datasource配置中对应的key
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
protected Object determineCurrentLookupKey() {
//使用自定义的DataSource选择器
return DynamicDataSourceHolder.getDataSource();
}
}
public class DynamicDataSourceHolder {
//保存当前线程所指定的DataSource
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 removeDataSource() {
THREAD_DATA_SOURCE.remove();
}
}
2、配置spring,创建多数据源
import com.alibaba.druid.pool.DruidDataSource;
import com.google.common.collect.Maps;
import com.sisheng.manhattan.data.multipart.core.DynamicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import java.util.LinkedHashMap;
@Configuration
public class MultipartDataSource {
/**
* 创建默认数据源
* @return
*/
@Bean
public DruidDataSource defaultSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("default");
dataSource.setPassword("default");
dataSource.setUrl("url");
return dataSource;
}
/**
* 创建测试数据源
* @return
*/
@Bean
public DruidDataSource testSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("test");
dataSource.setPassword("test");
dataSource.setUrl("url");
return dataSource;
}
/**
* 构建RoutingDataSource,用于选择配置的多个数据源
* @return
*/
@Bean
public DynamicDataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
LinkedHashMap<Object, Object> hashMap = Maps.newLinkedHashMap();
hashMap.put("default", defaultSource());
hashMap.put("test", testSource());
dynamicDataSource.setTargetDataSources(hashMap);
dynamicDataSource.setDefaultTargetDataSource(defaultSource());
return dynamicDataSource;
}
/**
* 构建事务管理器
* @return
*/
@Bean
public DataSourceTransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(this.dynamicDataSource());
return transactionManager;
}
}
3、定义aop,用于实现注解式数据源切换
import java.lang.annotation.*;
/**
* Description: 创建注解,用于指定aop拦截的切点
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceProxy {
//值得选取为类MultipartDataSource中dynamicDataSource()方法中hashmap的key
String value() default "default";
}
import com.sisheng.manhattan.data.multipart.core.DynamicDataSourceHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.springframework.core.annotation.AnnotationUtils;
import java.lang.reflect.Method;
/**
* Description: 定义aop,用于拦截DataSourceProxy注解的方法,实现数据源的切换
*/
@Aspect
public class DataSourceAdviceMulti {
//定义切点
@Pointcut(value = "@annotation(com.sisheng.manhattan.data.multipart.aspect.DataSourceProxy)")
private void anyMethod(){}//定义一个切入点
/**
* 方法执行前,切换到DataSourceProxy其value指定的数据源
* @param point
* @throws Throwable
*/
@Before("anyMethod()")
public void before(JoinPoint point) throws Throwable {
MethodSignature methodSignature = (MethodSignature) point.getSignature();
//获取被代理的方法对象
Method targetMethod = methodSignature.getMethod();
//获取被代理方法的注解信息
DataSourceProxy dataSourceProxy = AnnotationUtils.findAnnotation(targetMethod, DataSourceProxy.class);
if (dataSourceProxy != null) {
//设置数据库标志
DynamicDataSourceHolder.setDataSource(dataSourceProxy.value());
}
}
/**
* 释放数据源标志
*/
@AfterReturning("anyMethod()")
public void doAfter() {
DynamicDataSourceHolder.removeDataSource();
}
}
4、使用方法
import com.sisheng.manhattan.data.multipart.aspect.DataSourceProxy;
import org.springframework.stereotype.Service;
/**
* Description: 多数据源切换示例
*/
@Service
public class DataSourceService {
/**
* 指定数据源标志
*/
@DataSourceProxy(value = "test")
public void testDao() {
}
}