跳到主要内容

动态数据源的详细执行分析

在上一章节中,讲解了动态数据源对于数据中台项目存在的意义,那么从本章开始将详细的讲解项目中的动态数据源是如何加载并执行的

整体目标与思路

  • 核心职责AgilityRouteDataSource 作为整个应用唯一对外暴露的 DataSource Bean,负责在运行时基于上下文选择具体数据源并获取连接;在事务内对同一线程的多数据源连接进行集中管理与提交/回滚。
  • 关键配套
    • 属性装配与数据源创建:AgilityDataSourcePropertyAgilityYamlDataSourceObtain → 具体数据源实例(Hikari等)
    • 路由上下文:AgilityDataSourceHolder(ThreadLocal 栈)
    • 切换切面:AgilityDataSourceAspect(@AgilityDataSource)
    • 事务切面:AgilityTransactionAspect(@AgilityTransactional)
    • 事务持有:TransactionIdHolder(标识事务)与 TransactionMultiConnectionHolder(多数据源下的连接复用)
    • 自动装配:AgilityDataSourceAutoConfig(将 AgilityRouteDataSource 注册为主 DataSource

一、自动装配:把路由数据源注册为应用主 DataSource

启动时,自动装配类把 “属性解析 → 数据源创建 → 路由数据源” 一条链装起来,并提前于 Spring 默认数据源自动配置执行,保证全局唯一 DataSource 即为“路由数据源”。

@EnableConfigurationProperties(value = AgilityDataSourceProperty.class)
@AutoConfigureBefore(name = "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration")
public class AgilityDataSourceAutoConfig {

private final AgilityDataSourceProperty agilityDataSourceProperty;

public AgilityDataSourceAutoConfig(AgilityDataSourceProperty agilityDataSourceProperty) {
this.agilityDataSourceProperty = agilityDataSourceProperty;
}

@ConditionalOnClass(HikariDataSource.class)
@Bean
public DataSourceParse dataSourceParse(){
return new HikariDataSourceParse();
}
@Bean
public DataSourceCreatorHandler dataSourceCreatorHandler(DataSourceParse dataSourceParse){
return new DataSourceCreatorHandler(dataSourceParse);
}

@Bean
public AgilityDataSourceObtain agilityDataSourceObtain(DataSourceCreatorHandler dataSourceCreatorHandler) {
return new AgilityYamlDataSourceObtain(agilityDataSourceProperty.getDataSources(), dataSourceCreatorHandler);
}

@ConditionalOnMissingBean
@Bean
public DataSource agilityRouteDataSource(AgilityDataSourceObtain agilityDataSourceObtain){
return new AgilityRouteDataSource(agilityDataSourceObtain,agilityDataSourceProperty.getMaster());
}

属性模型与数据源创建器:

@Data
@ConfigurationProperties(prefix = AgilityDataSourceProperty.PREFIX)
public class AgilityDataSourceProperty {

public static final String PREFIX = "spring.datasource.agility";

/** 主数据源 */
private String master = DataSourceConstant.MASTER;

/** 所有数据源配置,key 就是 数据库 */
private Map<String, DataSourceProperty> dataSources = new HashMap<>();

@Data
public static class DataSourceProperty {

private Class<? extends DataSource> type;
private String url;
private String username;
private String password;
private String driverClassName;
}
}
@AllArgsConstructor
public class AgilityYamlDataSourceObtain implements AgilityDataSourceObtain {

private final Map<String, DataSourceProperty> dataSourcePropertyMap;

private final DataSourceCreatorHandler dataSourceCreatorHandler;


@Override
public Map<String, DataSource> obtainDataSource() {
Map<String, DataSource> dataSourceMap = MapUtil.newHashMap();
for (Entry<String, DataSourceProperty> entry : dataSourcePropertyMap.entrySet()) {
//规则配置创建具体的数据源
DataSource dataSource = dataSourceCreatorHandler.createDataSource(entry.getValue());
dataSourceMap.put(entry.getKey(), dataSource);
}
return dataSourceMap;
}
}

具体的配置

通过以上的属性和配置,能够将主数据源和其他数据源都会加载到Spring的bean中,SpringBoot中关于动态数据源的配置:

spring:
datasource:
agility:
master: d_collect_data
dataSources:
d_collect_data:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/d_collect_data?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
d_record:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/d_record?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root

二、AgilityRouteDataSource:动态路由与统一入口

AgilityRouteDataSource 实现了 AbstractDataSourceSmartDataSource,是全局统一的 DataSource 实例。核心职责有三:

  • 启动后集中“加载并缓存所有真实数据源”;
  • 运行时“依据上下文选择具体数据源”;
  • 事务内“同一数据源连接只创建一次并复用”。