Java多数据源切换核心是继承AbstractRoutingDataSource,重写determineCurrentLookupKey()返回非空key(如"master"),配合ThreadLocal存取数据源标识、setTargetDataSources注册真实数据源并设defaultTargetDataSource兜底,确保切换在事务前完成且线程安全。

Java 中抽象类规范多数据源切换的基础连接管理,核心在于用 AbstractRoutingDataSource 做统一出口,把“选哪个库”和“连哪个库”解耦开——它不直接持有真实数据源,而是按规则动态查路由、返回对应的数据源实例。
继承 AbstractRoutingDataSource 重写关键方法
这是最标准的起点。你需要定义一个子类(比如 DynamicDataSource),并强制实现 determineCurrentLookupKey() 方法:
- 该方法必须返回一个 Object 类型的 key(通常是 String,如 "master" 或 "slave1")
- 返回值会作为 lookupKey,去匹配你提前注册进 resolvedDataSources 映射表里的具体数据源 Bean
- 不能返回 null,否则启动时报错;建议配合默认数据源兜底
用 ThreadLocal 绑定当前线程的数据源标识
因为 HTTP 请求是单线程处理的,天然适合用 ThreadLocal 存储本次调用要走哪个库:
- 提供静态 setDataSourceKey(String key) 和 getDataSourceKey() 方法
- 在 AOP 切面或注解解析逻辑中调用 set,确保在 DAO/Service 方法执行前就设好
- determineCurrentLookupKey() 内部只需 return DataSourceContextHolder.getDataSourceKey() 即可
- 记得在请求结束时 clear(),避免线程复用导致脏数据(尤其在 Tomcat 线程池场景下)
数据源注册与默认策略要显式声明
AbstractRoutingDataSource 自身不创建数据源,只做路由分发。你需要主动注入所有候选数据源:
立即学习“Java免费学习笔记(深入)”;
- 在配置类里把多个 @Bean(如 masterDataSource、slaveDataSource)put 进 DynamicDataSource 的 setTargetDataSources(Map)
- 必须调用 setDefaultTargetDataSource(…) 设置一个兜底数据源(比如主库),防止 key 匹配失败
- 最后别忘了调用 afterPropertiesSet() 触发内部映射初始化,否则运行时报空指针
结合 Spring 生命周期做安全兜底
基础连接管理不只是“能切”,还要稳:
- 在 determineCurrentLookupKey() 中加非空校验,key 为空时自动 fallback 到默认源
- 数据源 Bean 上标注 @Primary 仅用于 Spring 自动装配场景,不影响 routing 行为
- 如果用 dynamic-datasource-spring-boot-starter 这类封装库,它的 AbstractRoutingDataSource 实现已内置健壮性逻辑,但仍需你控制好注解作用域和事务边界


















