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 切面编程概念 理解事务、日志拦截原理
扩展点 框架提供的抽象类/接口 能找到并实现扩展点

推荐学习资源


📌 阶段 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 验证,从模仿当前项目开始,逐步深入。

posted @ 2026-03-13 15:07  静水深耕,云停风驻  阅读(2)  评论(0)    收藏  举报