动态数据源配置
@Configuration
@Slf4j
public class DataSourceConfig {
@ConfigurationProperties("spring.datasource.one")
@Bean(initMethod = "init",destroyMethod = "close")
public DruidDataSource oneDatasource(){
log.debug("mysql one druid data-source init...");
return DruidDataSourceBuilder.create().build();
}
@ConfigurationProperties("spring.datasource.two")
@Bean(initMethod = "init",destroyMethod = "close")
public DruidDataSource twoDatasource(){
log.debug("mysql two druid data-source init...");
return DruidDataSourceBuilder.create().build();
}
@ConfigurationProperties("spring.datasource.three")
@Bean(initMethod = "init",destroyMethod = "close")
public DruidDataSource threeDatasource(){
log.debug("mysql three druid data-source init...");
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dataSource(@Qualifier("oneDatasource") DataSource one,
@Qualifier("twoDatasource") DataSource two,
@Qualifier("threeDatasource") DataSource three) {
Map<Object, Object> dsMap = Maps.newHashMapWithExpectedSize(INT_THREE);
dsMap.put("MASTER", one);
dsMap.put("SLAVE_2", two);
dsMap.put("SLAVE_3", three);
return new DynamicDataSource(dsMap, one);
}
}
AbstractRoutingDataSource
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<Stack<String>> DATA_SOURCE_KEY=new InheritableThreadLocal<>();
public static void setDataSourceKey(String dataSourceKey){
log.info("setDataSourceKey datasource{} ",dataSourceKey);
Stack<String> stack = DATA_SOURCE_KEY.get();
if(stack==null){
stack= new Stack<>();
DATA_SOURCE_KEY.set(stack);
}
stack.push(dataSourceKey);
}
public static void cleanDataSourceKey(){
Stack<String> stack = DATA_SOURCE_KEY.get();
if(stack!=null){
stack.pop();
if(stack.isEmpty()){
DATA_SOURCE_KEY.remove();
}
}
}
@Override
protected Object determineCurrentLookupKey() {
Stack<String> stack = DATA_SOURCE_KEY.get();
if(stack!=null){
return stack.peek();
}
return null;
}
public DynamicDataSource(Map<Object, Object> dataSourceMap,DataSource concurrentDatasource) {
super.setDefaultTargetDataSource(concurrentDatasource);
super.setTargetDataSources(dataSourceMap);
}
}
注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface SpecDataSource {
String value();
}
AOP
@Aspect
@Component
public class MethodSwitchDataSourceAspectJ implements Ordered {
@Pointcut("@annotation(com.spring.demo.test.config.datasource.annotation.SpecDataSource)")
public void pointcut() {
}
@Before(value = "pointcut() && @annotation(specDataSource)",argNames = "specDataSource")
public void before(SpecDataSource specDataSource){
DynamicDataSource.setDataSourceKey(specDataSource.value());
}
@After(value = "pointcut()")
public void after(){
DynamicDataSource.cleanDataSourceKey();
}
@Override
public int getOrder() {
return -2147483647;
}
}
@Aspect
@Component
public class TypeSwitchDataSourceAspectJ implements Ordered {
@Pointcut("@within(com.spring.demo.test.config.datasource.annotation.SpecDataSource)")
public void pointcut() {
}
@Before(value = "pointcut() && @within(specDataSource)",argNames = "specDataSource")
public void before(SpecDataSource specDataSource){
DynamicDataSource.setDataSourceKey(specDataSource.value());
}
@After(value = "pointcut()")
public void after(){
DynamicDataSource.cleanDataSourceKey();
}
@Override
public int getOrder() {
return -2147483646;
}
}