spring-boot-starter-dynamic-datasource
* 为了支持嵌套切换,如ABC三个service都是不同的数据源
* 其中A的某个业务要调B的方法,B的方法需要调用C的方法。一级一级调用切换,形成了链。
* 传统的只设置当前线程的方式不能满足此业务需求,必须使用栈,后进先出。
[18 tools called]
基于对 aiyong-spring-boot-starter-dynamic-datasource 模块的源码深度分析,我来为你详细讲解多数据源的原理、使用方式和事务处理机制。
这个多数据源实现基于Spring的AbstractRoutingDataSource,采用了以下关键设计:
核心组件:
DynamicRoutingDataSource: 主路由器,继承自AbstractRoutingDataSourceDynamicDataSourceContextHolder: 基于ThreadLocal的数据源上下文管理器DynamicDataSourceAnnotationInterceptor: AOP拦截器,处理@DS注解GroupDataSource: 数据源分组管理,支持负载均衡数据结构:
// 存储所有数据源
private final Map<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();
// 分组数据源,支持负载均衡
private final Map<String, GroupDataSource> groupDataSources = new ConcurrentHashMap<>();
graph TD
A["Method Call"] --> B["@DS Annotation"]
B --> C["AOP Interceptor"]
C --> D["Parse DataSource Key"]
D --> E["Push to ThreadLocal Stack"]
E --> F["determineDataSource()"]
F --> G["Get Key from ThreadLocal"]
G --> H{"Is Group DataSource?"}
H -->|"Yes"| I["GroupDataSource Load Balance"]
H -->|"No"| J["Get from dataSourceMap"]
I --> K["Return DataSource"]
J --> K
K --> L["Execute Business Logic"]
L --> M["Method End"]
M --> N["Pop ThreadLocal Stack"]
关键实现代码:
@Override
protected String getPrimary() {
return primary;
}
@Override
public DataSource determineDataSource() {
String dsKey = DynamicDataSourceContextHolder.peek();
return getDataSource(dsKey);
}