application.yml配置两个datasource
spring:
datasource:
first:
url: jdbc:mysql://xxxxxxxxx
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
second:
url: jdbc:mysql://xxxxxxxxx
username: root
password: 123456
driverClassName: com.mysql.jdbc.Driver
新建个DynamicDataSource
继承自AbstractRoutingDataSource,下面会说determineCurrentLookupKey的作用
public class DynamicDataSource extends AbstractRoutingDataSource {
public static ThreadLocal<String> key = new ThreadLocal<String>();
@Override
protected Object determineCurrentLookupKey() {
return key.get();
}
}
datasource的配置类:
使用@Primary DynamicDataSource作为默认数据源.
将两个基本数据源配置放到DynamicDataSource的数据源集合里面,然后设置默认是first
@Configuration
public class DatesourceConfig {
@ConfigurationProperties(prefix = "spring.datasource.first")
@Bean
DataSource first() {
return new DataSource();
}
@ConfigurationProperties(prefix = "spring.datasource.second")
@Bean
DataSource second() {
return new DataSource();
}
@Primary
@Bean
DynamicDataSource dynamicDataSource (@Qualifier("first") DataSource first,@Qualifier("second")DataSource second) {
DynamicDataSource dource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
targetDataSources.put("first", first);
targetDataSources.put("second", second);
dource.setTargetDataSources(targetDataSources);
dource.setDefaultTargetDataSource(first);
return dource;
}
}
DynamicDataSource有个targetDataSources的属性,里面放了一堆key-datasource的.
在实际mybaties需要数据源进行增删改查的时候,会通过determineCurrentLookupKey方法获取到key,然后通过key获取到datasource.如果没有获取到key,则会使用默认数据源
这里使用通过 ThreadLocal+注解+AOP 来传递determineCurrentLookupKey的key
创建注解DC
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD })
public @interface DC {
String value();
}
创建AOP,里面操作了Threadlocal
@Aspect
@Component
public class DataSourceAop {
@Around("@annotation(dc)")
public Object arround(ProceedingJoinPoint pjp, DC dc) {
DynamicDataSource.key.set(dc.value());
try {
Object o = pjp.proceed();
DynamicDataSource.key.remove();
return o;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
实际使用场景
@Service
public class AaaService {
//使用了second
@DC(value = "second")
public aaa() {
}
//使用默认的first
public aaa() {
}
}
可能在实际使用出现循环引用的问题,那么解除掉自动配置
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)