一、主要配置类列表展示
外加一个配置类DynamicDataSourceConfig.java
二、配置文件例如application-test.yml
spring:
# 数据源配置
datasource:
# 连接池配置
druid:
db1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
username: xxx
password: xxx
url: jdbc:mysql://xxx.xxx.xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
initialSize: 5
minIdle: 5
maxActive: 20
db2:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
username: xxx
password: xxx
url: jdbc:mysql://xxx.xxx.xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
initialSize: 5
minIdle: 5
maxActive: 20
servlet:
multipart:
max-file-size: 8MB
max-request-size: 8MB
三、DBTypeEnum
/**
* @author :cw
* @date :Created in 2020/6/10 下午12:04
* @description:
* @modified By:
* @version: $
*/
public enum DBTypeEnum {
DB_ONE("db1"),
DB_TWO("db2");
private String value;
DBTypeEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
四、DbContextHolder
/**
* @author :cw
* @date :Created in 2020/6/10 下午12:03
* @description:
* @modified By:
* @version: $
*/
public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal<>();
/**
* 设置数据源
* @param dbTypeEnum
*/
public static void setDbType(DBTypeEnum dbTypeEnum) {
contextHolder.set(dbTypeEnum.getValue());
}
/**
* 取得当前数据源
* @return
*/
public static String getDbType() {
return (String) contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clearDbType() {
contextHolder.remove();
}
}
五、DynamicDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @author :cw
* @date :Created in 2020/6/10 下午12:03
* @description:
* @modified By:
* @version: $
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* 取得当前使用哪个数据源
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
六、DBMapperConvert
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DBMapperConvert {
String value() default "";
}
七、DataSourceSwitchAspect
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author :cw
* @date :Created in 2020/6/10 下午12:12
* @description:
* @modified By:
* @version: $
*/
@Component
@Aspect
@Order(1) //这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高
@Slf4j
public class DataSourceSwitchAspect {
@Pointcut("@annotation(DBMapperConvert)")
private void dbChoose() {
}
@Before("dbChoose()")
public void convertDb(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
DBMapperConvert annotation = method.getAnnotation(DBMapperConvert.class);
String value = annotation.value();
if(DBTypeEnum.DB_ONE.getValue().equals(value)){
log.info("---------切换到 db1 数据源开始操作...:"+value);
DbContextHolder.setDbType(DBTypeEnum.DB_ONE);
}else(DBTypeEnum.DB_TWO.getValue().equals(value)){
log.info("--------切换到 db2 数据源开始操作...:"+value);
DbContextHolder.setDbType(DBTypeEnum.DB_TWO);
}
}
@After("dbChoose()")
public void afterPointcut(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
DBMapperConvert annotation = method.getAnnotation(DBMapperConvert.class);
String value = annotation.value();
log.info("---------切换到 "+value+" 数据源操作结束...:"+value);
DbContextHolder.c();
}
}
八、DynamicDataSourceConfig
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
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;
/**
* @author :cw
* @date :Created in 2020/6/10 上午11:56
* @description:
* @modified By:
* @version: $
*/
@Configuration
public class DynamicDataSourceConfig {
@Bean(name = "dbOne")
@ConfigurationProperties(prefix = "spring.datasource.druid.db1" )
public DataSource oneDb () {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "dbTwo")
@ConfigurationProperties(prefix = "spring.datasource.druid.db2" )
public DataSource twoDb () {
return DruidDataSourceBuilder.create().build();
}
/**
* 动态数据源配置
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource (@Qualifier("dbOne") DataSource dbOne,
@Qualifier("dbTwo") DataSource dbTwo) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map< Object, Object > targetDataSources = new HashMap<>(2);
targetDataSources.put(DBTypeEnum.DB_ONE.getValue(), dbOne );
targetDataSources.put(DBTypeEnum.DB_TWO.getValue(), dbTwo);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(dbOne);
return dynamicDataSource;
}
}
九、使用方式
@Override
@DBMapperConvert("db1")
public UserPo getTest1(String id){
UserPo userPo = dbOneMapper.getTest1(id);
return userPo;
}
@Override
@DBMapperConvert("db2")
public UserPo getTest2(String id){
UserPo userPo = dbTwoMapper.getTest2(id);
return userPo;
}
到此即可实现简单数据源的切换操作,待补充数据源动态操作配置