1.application.properties:
#default---开发环境
spring.datasource.default.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.default.jdbc-url=jdbc:oracle:thin:@10.XX.27.XX:1521:orcl
spring.datasource.default.username=aaa
spring.datasource.default.password=aaa
#datacenter---开发环境
spring.datasource.datacenter.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.datacenter.url=jdbc:mysql://10.XX.XX.XX:3403/db_cs?useUnicode=true&characterEncoding=UTF-8
spring.datasource.datacenter.username=bbb
spring.datasource.datacenter.password=bbb
2.编写数据源枚举类DataSourceEnum:
public enum DataSourceEnum{
DEFAULT_DS("default"),
DATA_CENTER_DS("datacenter");
DataSourceEnum(String key) {
this.key = key;
}
private String key;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
3.编写动态数据源类DynamicDataSource:
使用ThreadLocal,将不同线程隔离开,每个线程使用自己的数据源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
public class DynamicDataSource extends AbstractRoutingDataSource {
public static final ThreadLocal<String> DATA_SOURCE = new ThreadLocal<>();
public DynamicDataSource(DataSource dataSource, Map<Object, Object> dataSourceMap){
// 默认使用的数据源
super.setDefaultTargetDataSource(dataSource);
super.setTargetDataSources(dataSourceMap);
super.afterPropertiesSet();
}
// 这个方法返回的是当前线程使用的数据源key
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
public static void setDataSource(String dataSource){
DATA_SOURCE.set(dataSource);
}
public static String getDataSource(){
return DATA_SOURCE.get();
}
public static void removeDataSource(){
DATA_SOURCE.remove();
}
}
4.编写动态数据源配置类DynamicDataSourceConfig:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
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("defaultDataSource")
@ConfigurationProperties("spring.datasource.default")// 对应application.properties中的配置
public DataSource defaultDataSource(){
return DataSourceBuilder.create().build();
}
@Bean("dataCenterDataSource")
@ConfigurationProperties("spring.datasource.datacenter")
public DataSource dataCenterDataSource(){
return DataSourceBuilder.create().build();
}
@Primary //默认数据源配置
@Bean
public DynamicDataSource dataSource(@Qualifier("defaultDataSource") DataSource defaultDataSource , @Qualifier("dataCenterDataSource") DataSource dataCenterDataSource){
Map<Object, Object> map = new HashMap<>();
map.put(DataSourceEnum.DEFAULT_DS.getKey(), defaultDataSource);
map.put(DataSourceEnum.DATA_CENTER_DS.getKey(), dataCenterDataSource);
return new DynamicDataSource(defaultDataSource, map);
}
}
5.编写注解类DS:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)// 运行时使用
@Target({ElementType.METHOD}) // 方法级注解
public @interface DS {
DataSourceEnum name() default DataSourceEnum.DEFAULT_DS;
}
6.编写切面类DataSourceAspect:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
@Order(-1)
public class DataSourceAspect {
@Around("@annotation(com.yunda.config.DS)")
public Object around(ProceedingJoinPoint point) throws Throwable{
MethodSignature signature = (MethodSignature)point.getSignature();
Method method = signature.getMethod();
DS ds = method.getAnnotation(DS.class);
if(ds == null){
DynamicDataSource.setDataSource(DataSourceEnum.DEFAULT_DS.getKey());
System.out.println(Thread.currentThread().getName() + ": dataSource is " + DataSourceEnum.DEFAULT_DS.getKey());
}else{
DynamicDataSource.setDataSource(ds.name().getKey());
System.out.println(Thread.currentThread().getName() + ": dataSource is " + ds.name().getKey());
}
try {
return point.proceed();
} finally {
DynamicDataSource.removeDataSource();
System.out.println(Thread.currentThread().getName() + ": remove dataSource");
}
}
}
7.开启切面自动代理,关闭默认数据源配置:
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@EnableFeignClients
@EnableAspectJAutoProxy
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}