java -- mybatis 学习流程
determineCurrentLookupKey 学习路径指南
[determineCurrentLookupKey](file://d:\SRC\java\SuperInsight\DBaaS\server\src\main\java\com\zte\ws\service\gdb\impl\DynamicDataSource.java#L40-L44) 是 Spring 框架扩展点 的典型示例。以下是系统的学习步骤:
1. 理解方法来源
1.1 框架定位
Spring Framework
└─ spring-jdbc 模块
└─ org.springframework.jdbc.datasource.lookup
└─ AbstractRoutingDataSource (抽象类)
└─ determineCurrentLookupKey() (抽象方法)
核心作用:Spring 提供的 数据源路由扩展点,让开发者自定义路由逻辑。
1.2 源码结构
// Spring 源码简化版
public abstract class AbstractRoutingDataSource implements DataSource {
private Map<Object, DataSource> targetDataSources;
private Object defaultTargetDataSource;
@Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
protected DataSource determineTargetDataSource() {
Object lookupKey = determineCurrentLookupKey(); // ← 调用子类实现
return targetDataSources.get(lookupKey);
}
// 抽象方法,由子类实现
protected abstract Object determineCurrentLookupKey();
}
2. 设计模式理解
2.1 模板方法模式 (Template Method)
┌─────────────────────────────────────────────────────────────────┐
│ AbstractRoutingDataSource │
│ (父类 - 定义算法骨架) │
├─────────────────────────────────────────────────────────────────┤
│ getConnection() // 固定流程 │
│ determineTargetDataSource() // 固定流程 │
│ determineCurrentLookupKey() // 抽象方法,子类实现 │
└─────────────────────────────────────────────────────────────────┘
↑ 继承
┌─────────────────────────────────────────────────────────────────┐
│ DynamicDataSource │
│ (子类 - 实现具体步骤) │
├─────────────────────────────────────────────────────────────────┤
│ @Override │
│ determineCurrentLookupKey() { │
│ return ContextHolder.getDataSourceKey(); // 自定义逻辑 │
│ } │
└─────────────────────────────────────────────────────────────────┘
2.2 策略模式 (Strategy)
路由策略
├─ 方案 1: ThreadLocal 上下文 (当前项目)
│ └─ DynamicDataSourceContextHolder.getDataSourceKey()
├─ 方案 2: 请求头解析
│ └─ HttpServletRequest.getHeader("X-Tenant-Id")
├─ 方案 3: 用户身份
│ └─ SecurityContextHolder.getAuthentication()
└─ 方案 4: 数据库字段
└─ 查询配置表动态决定
3. 系统学习步骤
📌 阶段 1:Java 基础 (1-2 周)
| 知识点 | 学习内容 | 实践目标 |
|---|---|---|
| 抽象类 | abstract class 语法 |
能定义抽象方法和具体方法 |
| 继承 | extends 关键字 |
理解子类如何重写父类方法 |
| 接口 | interface 语法 |
理解接口与抽象类的区别 |
| 多态 | 父类引用指向子类对象 | 理解运行时方法绑定 |
练习代码:
// 练习 1:定义抽象类
abstract class DataSource {
public Connection getConnection() {
String key = getLookupKey(); // 调用抽象方法
return createConnection(key);
}
protected abstract String getLookupKey();
protected abstract Connection createConnection(String key);
}
// 练习 2:实现子类
class MyDataSource extends DataSource {
@Override
protected String getLookupKey() {
return "mysql";
}
@Override
protected Connection createConnection(String key) {
// 创建连接逻辑
}
}
📌 阶段 2:Spring 框架基础 (2-3 周)
| 知识点 | 学习内容 | 实践目标 |
|---|---|---|
| IoC 容器 | Bean 的创建和管理 | 理解 @Component、@Bean |
| 依赖注入 | @Autowired、构造函数注入 |
能注入 Mapper、Service |
| AOP | 切面编程概念 | 理解事务、日志拦截原理 |
| 扩展点 | 框架提供的抽象类/接口 | 能找到并实现扩展点 |
推荐学习资源:
- 官方文档:https://spring.io/projects/spring-framework
- 书籍:《Spring 实战第 5 版》
- 视频:B 站 Spring 源码解析系列
📌 阶段 3:Spring JDBC 模块 (1-2 周)
| 类/接口 | 作用 | 学习重点 |
|---|---|---|
| [DataSource](file://d:\SRC\java\SuperInsight\DBaaS\server\src\main\java\com\zte\ws\service\gdb\impl\DynamicDataSource.java#L17-L17) | JDBC 数据源接口 | 理解 getConnection() |
AbstractRoutingDataSource |
路由数据源基类 | 理解路由机制 |
TransactionSynchronizationManager |
事务同步管理器 | 理解事务上下文 |
DataSourceTransactionManager |
事务管理器 | 理解多数据源事务 |
练习代码:
// 练习:实现自己的路由数据源
@Component
public class MyRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
// 从请求上下文获取租户 ID
return TenantContext.getCurrentTenantId();
}
}
📌 阶段 4:阅读 Spring 源码 (2-3 周)
源码阅读顺序:
1. AbstractRoutingDataSource.java
└─ 理解 determineTargetDataSource() 流程
2. DataSourceTransactionManager.java
└─ 理解事务如何绑定数据源
3. SqlSessionUtils.java (MyBatis-Spring)
└─ 理解 MyBatis 如何获取连接
4. DynamicDataSource.java (当前项目)
└─ 理解业务场景下的实现
源码阅读技巧:
# 1. 找到方法定义
grep -r "determineCurrentLookupKey" spring-jdbc/src
# 2. 查看调用栈
IDE 中右键 → Find Usages
# 3. 调试跟踪
在方法处打断点 → 查看调用链
📌 阶段 5:实战项目 (持续)
由简到繁的练习项目:
| 项目 | 难度 | 学习目标 |
|---|---|---|
| 主从数据源切换 | ⭐ | 读写分离 |
| 多租户数据源路由 | ⭐⭐ | 类似当前项目 |
| 动态添加/移除数据源 | ⭐⭐⭐ | 类似 [addDataSource](file://d:\SRC\java\SuperInsight\DBaaS\server\src\main\java\com\zte\ws\service\gdb\impl\DynamicDataSource.java#L152-L165) |
| 数据源健康检查 | ⭐⭐⭐ | 类似 [printDataSourceStats](file://d:\SRC\java\SuperInsight\DBaaS\server\src\main\java\com\zte\ws\service\gdb\impl\DynamicDataSource.java#L168-L184) |
| 分布式数据源管理 | ⭐⭐⭐⭐ | 结合配置中心 |
4. 类似框架扩展点汇总
掌握 [determineCurrentLookupKey](file://d:\SRC\java\SuperInsight\DBaaS\server\src\main\java\com\zte\ws\service\gdb\impl\DynamicDataSource.java#L40-L44) 后,可类比学习以下扩展点:
| 框架 | 扩展点方法 | 作用 |
|---|---|---|
| Spring | HandlerInterceptor.preHandle() |
请求拦截 |
| Spring | Advice.before()/after() |
AOP 切面 |
| MyBatis | TypeHandler.setParameter() |
类型转换 |
| MyBatis | ObjectFactory.create() |
对象创建 |
| Spring Boot | ApplicationContextInitializer.initialize() |
容器初始化 |
| Spring Security | UserDetailsService.loadUserByUsername() |
用户加载 |
共同模式:
框架定义抽象方法 → 开发者实现具体逻辑 → 框架在适当时机调用
5. 学习资源推荐
📚 书籍
| 书名 | 适用阶段 | 重点章节 |
|---|---|---|
| 《Spring 实战》 | 入门 | 第 3 章 Bean、第 4 章 AOP |
| 《Spring 源码深度解析》 | 进阶 | 数据源、事务章节 |
| 《Effective Java》 | 基础 | 第 2 章对象、第 4 章类 |
🌐 在线资源
| 资源 | 链接 | 说明 |
|---|---|---|
| Spring 官方文档 | spring.io | 最权威 |
| Spring GitHub | github.com/spring-projects/spring-framework | 源码 |
| Baeldung | baeldung.com | Spring 教程 |
| 美团技术博客 | tech.meituan.com | 实战案例 |
🛠️ 实践工具
| 工具 | 用途 |
|---|---|
| IDEA Debug | 断点跟踪调用栈 |
| Arthas | 线上方法调用追踪 |
| Spring Boot Actuator | 监控数据源状态 |
6. 学习检查清单
完成以下任务检验学习效果:
□ 能解释 abstract 关键字的作用
□ 能说出模板方法模式的特点
□ 能找到 AbstractRoutingDataSource 的源码位置
□ 能画出 determineCurrentLookupKey 的调用栈
□ 能独立实现一个多数据源路由 Demo
□ 能解释 ThreadLocal 在数据源切换中的作用
□ 能处理多数据源事务问题
□ 能动态添加/移除数据源
7. 总结
学习路径
├─ Java 基础 (抽象类、继承、多态)
├─ Spring 基础 (IoC、AOP、Bean)
├─ Spring JDBC (DataSource、事务)
├─ 源码阅读 (AbstractRoutingDataSource)
└─ 实战项目 (多数据源路由)
核心思维
├─ 理解框架扩展点的设计意图
├─ 掌握"框架定义 - 开发者实现"的协作模式
├─ 学会阅读源码追踪调用链
└─ 通过实战巩固理论知识
关键建议:不要只看不练,每学一个知识点都要写 Demo 验证,从模仿当前项目开始,逐步深入。

浙公网安备 33010602011771号