springboot继承AbstractRoutingDataSource可以实现数据源。
1.先写继承AbstractRoutingDataSource的类
(1).DynamicDataSource 是设置默认数据源和已经存在的所有数据源
(2).这个determineCurrentLookupKey是从当前线程获取设置的数据源
public class DynamicDataSource extends AbstractRoutingDataSource
{
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
{
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey()
{
return DynamicDataSourceContextHolder.getDateSoureType();
}
}
2.DynamicDataSourceContextHolder设置当前线程处理数据源的类
public class DynamicDataSourceContextHolder {
public static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
private static final ThreadLocal<String> DATASOURCE_CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 设置数据源
*/
public static void setDateSoureType(String dateSoureType) {
logger.info("设置数据源={}", dateSoureType);
DATASOURCE_CONTEXT_HOLDER.set(dateSoureType);
}
/**
* 获得数据源
*/
public static String getDateSoureType() {
return DATASOURCE_CONTEXT_HOLDER.get();
}
/**
* 清空数据源
*/
public static void clearDateSoureType() {
DATASOURCE_CONTEXT_HOLDER.remove();
}
}
3.配置Hikari数据源和包位置
@Configuration
@MapperScan("com.fast.framework.dao")
public class HikariCustomConfig {
public static final Logger logger = LoggerFactory.getLogger(HikariCustomConfig.class);
@Value("${mybatis.config-location}")
private String configLocation;
@Value("${mybatis.type-aliases-package}")
private String typeAliasespackage;
@Bean("master")
@ConfigurationProperties(prefix = "spring.datasource.hikari.master")
public HikariDataSource masterDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean("second")
@ConfigurationProperties(prefix = "spring.datasource.hikari.second")
public HikariDataSource slaveDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean(name = "dynamicDataSource")
public DynamicDataSource dataSource(@Qualifier("master") DataSource masterDataSource, @Qualifier("second") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(AllDatasource.MASTER.name(), masterDataSource);
targetDataSources.put(AllDatasource.SECOND.name(), slaveDataSource);
return new DynamicDataSource(masterDataSource, targetDataSources);
}
/**
* @description: 配置mybatis的mapper和dao的位置
*/
@Bean("sqlSessionFactoryBean")
public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource);
sqlSessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources(configLocation));
sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasespackage);
return sqlSessionFactoryBean;
}
/**
* 事务管理
*/
@Bean
public PlatformTransactionManager transactionManager(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
}
4.设置aop注解,通过注解设置数据源
@Aspect
@Order(1)
@Component
public class DataSourceAop {
@Value("${spring.datasource.hikari.master.default-package}")
private String masterPackage;
@Value("${spring.datasource.hikari.second.default-package}")
private String secondPackage;
public static final Logger logger = LoggerFactory.getLogger(DataSourceAop.class);
@Pointcut("execution(* com.fast.framework.dao..*.*(..)) ||@annotation(com.fast.common.annotation.ChooseDataSource)")
public void switchDataSource() {
}
@Before("switchDataSource()")
public void doBefore(JoinPoint joinPoint) {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
ChooseDataSource chooseDataSource = method.getAnnotation(ChooseDataSource.class);//获取方法上的注解
if (chooseDataSource == null) {
chooseDataSource = joinPoint.getTarget().getClass().getAnnotation(ChooseDataSource.class);//获取类上面的注解
if (chooseDataSource == null) {
String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
if (declaringTypeName.startsWith(masterPackage)) {
DynamicDataSourceContextHolder.setDateSoureType(AllDatasource.MASTER.name());
logger.info("使用包默认数据源,包={},数据源={}", masterPackage, AllDatasource.MASTER.name());
} else if (declaringTypeName.startsWith(secondPackage)) {
DynamicDataSourceContextHolder.setDateSoureType(AllDatasource.SECOND.name());
logger.info("使用包默认数据源,包={},数据源={}", secondPackage, AllDatasource.SECOND.name());
}
return;
} else {
logger.info("类注解生效,切换数据源={}", chooseDataSource.dataSource().name());
}
} else {
logger.info("方法注解生效,切换数据源={}", chooseDataSource.dataSource().name());
}
//获取注解上的数据源的值的信息
String dataSourceName = chooseDataSource.dataSource().name();
if (dataSourceName != null) {
//给当前的执行SQL的操作设置特殊的数据源的信息
DynamicDataSourceContextHolder.setDateSoureType(dataSourceName);
}
String nowDatasource = "".equals(dataSourceName) ? "默认数据源master" : dataSourceName;
logger.info("AOP注解切换数据源,className" + joinPoint.getTarget().getClass().getName() + "methodName" + method.getName() + ";dataSourceName:" + nowDatasource);
}
@After("switchDataSource()")
public void after(JoinPoint point) {
//清理掉当前设置的数据源,让默认的数据源不受影响
DynamicDataSourceContextHolder.clearDateSoureType();
}
}
5.配置数据源和包位置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
hikari:
driver-class-name: com.mysql.cj.jdbc.Driver
maximum-pool-size: 20
max-lifetime: 30000
idle-timeout: 30000
master:
default-package: com.fast.framework.dao.master
jdbc-url: jdbc:mysql://localhost:3306/fastblack?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=true
username: root
password: 123456
second:
default-package: com.fast.framework.dao.second
jdbc-url: jdbc:mysql://localhost:3306/base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=true
username: root
password: 123456
mybatis:
config-location: classpath*:/mapper/*/*.xml
type-aliases-package: com.fast.framework.model
6.枚举和切换数据源注解
public enum AllDatasource {
MASTER,
SECOND;
}
注解:
/**
* @Auther: Administrator
* @Date: 2019/6/9 16:36
* @Description:设置数据源 优先级:1.方法注解 2.类注解 3.根据包路径设置的数据源
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChooseDataSource {
AllDatasource dataSource() default AllDatasource.MASTER;
}
最后,这个是经过测试可以使用的,各位需要有基础,配置的时候直接拷贝修改一下就好了。