application.yml
spring:
datasource:
druid:
d1:
url: jdbc:mysql://xxx
username: xxx
password: xxx
driverClassName: com.mysql.jdbc.Driver
initial-size: 1
max-active: 1
min-idle: 1
test-on-borrow: true
validation-query: select 1
min-evictable-idle-time-millis: 500000
max-evictable-idle-time-millis: 600000
d2:
url: jdbc:mysql://xxx
username: xxx
password: xxx
driverClassName: com.mysql.jdbc.Driver
initial-size: 1
max-active: 1
min-idle: 1
test-on-borrow: true
validation-query: select 1
connection-init-sqls: SET NAMES utf8mb4
多数据源配置
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
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 javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DynamicDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.d1")
public DataSource d1() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.d2")
public DataSource d2() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dataSource(DataSource d1, DataSource d2) {
Map<Object, Object> targetDataSources = new HashMap<>(2);
targetDataSources.put("d1", myDataSource1);
targetDataSources.put("d2", myDataSource2);
return new DynamicDataSource(myDataSource1, myDataSource2);
}
}
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 配置DataSource, defaultTargetDataSource为主数据库
*/
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
public static void setDataSource(String dataSource) {
CONTEXT_HOLDER.set(dataSource);
}
public static String getDataSource() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSource() {
CONTEXT_HOLDER.remove();
}
}
定义注解
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
String name() default "d1";
}
定义切面
@Aspect
@Slf4j
@Configuration
public class TargetDataSourceAspect implements Ordered {
@Override
public int getOrder() {
return 1;
}
@Around("@within(com.xxx.annotation.DS) " +
"|| @annotation(com.xxx.annotation.DS)")
public Object around(ProceedingJoinPoint point) throws Throwable {
DS annotationInClass = AnnotationUtils.findAnnotation(point.getTarget().getClass(), DS.class);
if (annotationInClass == null) {
log.warn("DS annotationInClass get fail");
return point.proceed();
}
String name = annotationInClass.name();
DynamicDataSource.setDataSource(name);
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
}
}
}
SpringApplication记得开启AOP
使用示例:
@Service
@DS(name = "d1")
public class MyService {
...省略业务代码
}