1.数据库配置
spring:
datasource:
default:
url: jdbc:mysql://localhost:3306/maindb
username: default
password: depassword
driver-class-name: com.mysql.cj.jdbc.Driver
second:
url: jdbc:mysql://localhost:3306/seconddb
username: second
password: secondpassword
driver-class-name: com.mysql.cj.jdbc.Driver
2.创建数据源Bean
@Configuration
@EnableTransactionManagement
public class MultipleDataSourceConfig {
@Bean(name ="default")
@ConfigurationProperties(prefix = "spring.datasource.default")
public DataSource default(){
return DataSourceBuilder.create.build():
}
@Bean(name ="second")
@ConfigurationProperties(prefix = "spring.datasource.second")
public DataSource second(){
return DataSourceBuilder.create.build():
}
}
public class DynamicDataSourceContext(){
private static ThreadLocal<String> contextHolder = null;
synchronized public static ThreadLocal<String> getInstance() {
if (contextHolder == null) {
contextHolder = new ThreadLocal<>();
}
return contextHolder;
}
public static void setDataSource(String dataSource) {
getInstance().set(dataSource);
}
public static String getDataSource(){
return Objects.isNull(getInstance().get()) ? "default": getDataSource().get();
}
public static void clearDataSource(){
getInstance().remove();
}
}
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey(){
return DynamicDataSourceContext.getDataSource();
}
}
@Configuration
public class DynamicDataSourceConfig {
@Bean
@Primary
public DataSource dataSOurce(@Qualifier("default") DataSource defeult,@Qualifier("second") DataSource second){
Map<Object,Object> datasource = new HashMap();
datasource.put("default",defeult);
datasource.put("second",second);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(datasource);
dynamicDataSource.setDefaultTargetDataSource(default);
return dynamicDataSource;
}
}
3.定义注解,设置具体数据源
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicDataSourceSwitch {
String value() default "default";
}
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(xx.xx.xxx.DynamicDataSourceSwitch)")
public void myCustomAnnotationPointcut() {
}
@Before("myCustomAnnotationPointcut()")
public void beforeMyCustomAnnotation( JoinPoint point) {
Signature signature = point.getSignature();
DynamicDataSourceSwitch switercher;
if(signature instanceof MethodSignature ms){
switercher = ms.getMethod().getAnnotation(DynamicDataSourceSwitch.class);
if(Objects.isNull(switercher)){
switercher = (DynamicDataSourceSwitch)signature.getDeclaringType().getAnnotation(DynamicDataSourceSwitch.class);
}
if(Objects.nonNull(switercher)) {
DynamicDataSourceContext.setDataSource(switercher.value);
}
}
}
@After("myCustomAnnotationPointcut()")
public void afterMyCustomAnnotation(JoinPoint point) {
DynamicDataSourceContext.clearDataSource();
}
@AfterThrowing(pointcut = "myCustomAnnotationPointcut()")
public void afterThrowingMyCustomAnnotation(JoinPoint point) {
DynamicDataSourceContext.clearDataSource();
}
}
4.使用
@Service
@DynamicDataSourceSwitch("second")
public class TestService {
public void test(){
}
}
- 备注:若不想显示指定,还可以在拦截器中拦截,根据路径或者header里的信息来指定数据源