| Componant |
Implementation |
| DataSource Annotation |
DataSource.java |
| AspectJ Implementation |
DataSourceAspect.java |
| Data Source Constants |
DataSourceConstants.java |
| Dynamic Data Source |
DynamicDataSource.java |
| Configuration |
DataSourceConfig.java |
DataSource Annotation
package com.example.datasource.config;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default "";
}
AspectJ Implementation
package com.example.datasource.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DataSourceInterceptor implements Ordered {
@Pointcut("@annotation(DataSource)")
public void dataSourcePointcut() {}
@Around("dataSourcePointcut()")
public Object switchDataSource(ProceedingJoinPoint pjp) throws Throwable {
DataSource annotation = getDataSourceAnnotation(pjp);
String dsName = annotation != null ? annotation.name() : DataSourceConstants.PRIMARY;
DynamicDataSource.setCurrentDataSource(dsName);
try {
return pjp.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
private DataSource getDataSourceAnnotation(ProceedingJoinPoint pjp) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
return signature.getMethod().getAnnotation(DataSource.class);
}
@Override
public int getOrder() {
return 1;
}
}
Data Source Constants
package com.example.datasource.config;
public class DataSourceConstants {
public static final String PRIMARY = "primary";
public static final String SECONDARY = "secondary";
}
Dynamic Data Source
package com.example.datasource.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.util.Map;
import com.alibaba.druid.pool.DruidDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<string> currentDataSource = new ThreadLocal<>();
public DynamicDataSource(DruidDataSource defaultDs, Map<object object=""> targetDataSources) {
super.setDefaultTargetDataSource(defaultDs);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return currentDataSource.get();
}
public static void setCurrentDataSource(String dsName) {
currentDataSource.set(dsName);
}
public static void clearDataSource() {
currentDataSource.remove();
}
}
</object></string>
Configuration
package com.example.datasource.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.primary")
public DruidDataSource primaryDataSource() {
return new DruidDataSource();
}
@Bean
@ConfigurationProperties("spring.datasource.secondary")
public DruidDataSource secondaryDataSource() {
return new DruidDataSource();
}
@Bean
@Primary
public DynamicDataSource routingDataSource(
DruidDataSource primaryDataSource,
DruidDataSource secondaryDataSource) {
Map<object object=""> dataSources = new HashMap<>();
dataSources.put(DataSourceConstants.PRIMARY, primaryDataSource);
dataSources.put(DataSourceConstants.SECONDARY, secondaryDataSource);
return new DynamicDataSource(primaryDataSource, dataSources);
}
}
</object>