本文主要是介绍SpringBoot实现【动态数据源配置】这一篇就够了,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
实现动态数据源配置
- 0. 排除数据源的自动装配
- 1. yml配置多个数据源信息
- 2. 使用ThreadLocal,保存数据源名称供下游业务使用
- 3. 定义数据源类,继承AbstractRoutingDataSource
- 4. 定义配置类读取数据源信息,设置数据源对象属性
- 5. 定义自定义数据源注解
- 6. 定义切面,设置数据源名到ThreadLocal中
- 7. 使用动态数据源
0. 排除数据源的自动装配
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
1. yml配置多个数据源信息
spring:datasource:master:driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.124.200:3306/monitorusername: rootpassword: rootsalve:driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.124.201:3306/monitorusername: rootpassword: root
2. 使用ThreadLocal,保存数据源名称供下游业务使用
public class DataSourceContextHolder {private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();// 设置数据源名public static void setDataSource(String dbName) {contextHolder.set(dbName);}// 获取数据源名public static String getDataSource() {return (contextHolder.get());}// 清除数据源名public static void clearDataSource() {contextHolder.remove();}
}
3. 定义数据源类,继承AbstractRoutingDataSource
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSource();}}
4. 定义配置类读取数据源信息,设置数据源对象属性
@Configuration
public class DataSourceConfig {@Bean@ConfigurationProperties("spring.datasource.master")public DataSource master(){return DataSourceBuilder.create().build();}@Bean@ConfigurationProperties("spring.datasource.slave")public DataSource slave(){return DataSourceBuilder.create().build();}@Primary@Beanpublic DynamicDataSource dataSource(DataSource master, DataSource slave) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("master", master);targetDataSources.put("slave", slave);DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(targetDataSources);return dynamicDataSource;}
}
5. 定义自定义数据源注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface DS {String value() default "master";
}
6. 定义切面,设置数据源名到ThreadLocal中
@Component
@Aspect
public class DynamicDataSourceAspect {@Pointcut("@annotation(com.iteng.annotation.DS)")public void dynamicDataSourcePointCut() {}@Around("dynamicDataSourcePointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {String dataSourceKey;// 类上的注解Class<?> aClass = joinPoint.getTarget().getClass();DS annotation = aClass.getAnnotation(DS.class);// 方法上的注解MethodSignature signature = (MethodSignature) joinPoint.getSignature();DS annotationMethod = signature.getMethod().getAnnotation(DS.class);if (Objects.nonNull(annotationMethod)) {dataSourceKey = annotationMethod.value();} else {dataSourceKey = annotation.value();}// 设置数据源DataSourceContextHolder.setDataSource(dataSourceKey);try {return joinPoint.proceed();}finally {DataSourceContextHolder.clearDataSource();}}
}
7. 使用动态数据源
@DS(value = "salve")
@GetMapping("/get")
public R getName(){// 数据库操作
}@DS
@PostMapping("/save")
public R sageName(){// 数据库操作
}
流程:
- getName() 方法在执行之前,先执行对应的切面类,将“
salve
”这个数据源名称保存带ThreadLocal中 - 然后执行getName() 方法,当遇到数据库操作时,首先要与数据库进行连接。
- MyBatis 会先找
DataSource
的实现类,因为 DataSource 有getConnection()
方法。 - 继承了 AbstractRoutingDataSource 的
DynamicDataSource
会被找到。 - 然后执行 DynamicDataSource 中的
determineTargetDataSource
方法,即确定AbstractRoutingDataSource
中 Map 对应的Key,然后获取对应的数据源对象。 - 进行数据库连接。
这篇关于SpringBoot实现【动态数据源配置】这一篇就够了的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!