Appearance
MyBatis 源码分析
深入 MyBatis 源码,理解核心组件的工作机制,掌握 Mapper 代理、SQL 执行、插件拦截等底层原理。
一、源码架构全景
MyBatis 核心包结构:
org.apache.ibatis
├── session/ → SqlSession、SqlSessionFactory
├── executor/ → Executor 执行器
├── mapping/ → MappedStatement、BoundSql
├── scripting/ → 动态 SQL 解析
├── binding/ → Mapper 代理绑定
├── builder/ → 配置解析(XML 解析)
├── plugin/ → 插件机制
├── cache/ → 缓存
├── transaction/ → 事务管理
├── datasource/ → 数据源
├── reflection/ → 反射工具
├── logging/ → 日志
└── type/ → 类型处理器二、配置文件解析流程
mybatis-config.xml 解析流程:
SqlSessionFactoryBuilder.build(InputStream)
│
▼
XMLConfigBuilder.parse()
│
├── 解析 <properties> → 变量
├── 解析 <settings> → Configuration 全局设置
├── 解析 <typeAliases> → 别名注册
├── 解析 <typeHandlers> → 类型处理器注册
├── 解析 <plugins> → 拦截器链
├── 解析 <environments> → 数据源 + 事务管理器
├── 解析 <databaseIdProvider> → 数据库厂商标识
└── 解析 <mappers> → 解析 Mapper XML
│
▼
返回 Configuration 对象
│
▼
创建 DefaultSqlSessionFactory(Configuration)关键类:
XMLConfigBuilder → 解析 mybatis-config.xml
XMLMapperBuilder → 解析每个 Mapper XML
XMLStatementBuilder → 解析每个 <select>/<insert>/<update>/<delete>
MapperAnnotationBuilder → 解析 Mapper 接口注解三、Mapper 代理原理
问题:UserMapper 是一个接口,没有实现类,为什么能执行 SQL?
答案:MyBatis 通过 JDK 动态代理 生成 MapperProxy 代理对象java
// 源码核心流程(简化版)
// ① 获取 Mapper 时创建代理
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// MapperRegistry
MapperProxyFactory<T> mapperProxyFactory = knownMappers.get(type);
return mapperProxyFactory.newInstance(sqlSession);
}
// ② MapperProxyFactory 创建代理
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return (T) Proxy.newProxyInstance(
mapperInterface.getClassLoader(),
new Class[]{mapperInterface},
mapperProxy
);
}
// ③ MapperProxy.invoke() 拦截所有方法调用
public Object invoke(Object proxy, Method method, Object[] args) {
// 如果是 Object 的方法(toString、hashCode 等),直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
// 缓存 MapperMethod
MapperMethod mapperMethod = cachedMapperMethod(method);
// 执行 SQL
return mapperMethod.execute(sqlSession, args);
}
// ④ MapperMethod.execute() 分发到 SqlSession
public Object execute(SqlSession sqlSession, Object[] args) {
switch (command.getType()) {
case INSERT: return sqlSession.insert(command.getName(), param);
case UPDATE: return sqlSession.update(command.getName(), param);
case DELETE: return sqlSession.delete(command.getName(), param);
case SELECT:
if (returnsMany) return sqlSession.selectList(command.getName(), param);
if (returnsMap) return sqlSession.selectMap(command.getName(), param, ...);
return sqlSession.selectOne(command.getName(), param);
}
}执行流程总结:
接口方法调用 → MapperProxy.invoke() → MapperMethod.execute()
→ SqlSession.xxx() → Executor.xxx() → StatementHandler → JDBC四、Executor 源码
java
// Executor 接口
public interface Executor {
int update(MappedStatement ms, Object parameter);
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler);
void commit(boolean required);
void rollback(boolean required);
Transaction getTransaction();
CacheKey createCacheKey(MappedStatement ms, Object parameter, ...);
// ...
}BaseExecutor 一级缓存实现:
java
// BaseExecutor.query() 一级缓存逻辑(简化版)
public <E> List<E> query(MappedStatement ms, Object parameter, ...) {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// ① 先查一级缓存
List<E> list = (List<E>) localCache.getObject(key);
if (list != null) {
return list;
}
// ② 缓存没命中,查数据库
list = queryFromDatabase(ms, parameter, rowBounds, ...);
// ③ 放入一级缓存
localCache.putObject(key, list);
return list;
}
// 增删改清空缓存
public int update(MappedStatement ms, Object parameter) {
clearLocalCache(); // 清空一级缓存
return doUpdate(ms, parameter);
}CachingExecutor 二级缓存实现:
java
// CachingExecutor.query() 二级缓存逻辑(简化版)
public <E> List<E> query(MappedStatement ms, Object parameter, ...) {
Cache cache = ms.getCache(); // 获取二级缓存
if (cache != null) {
CacheKey key = createCacheKey(ms, parameter, ...);
// ① 先查二级缓存
List<E> list = (List<E>) cache.getObject(key);
if (list != null) {
return list;
}
}
// ② 二级缓存没命中,委托给 BaseExecutor(一级缓存 + 数据库)
return delegate.query(ms, parameter, ...);
}五、StatementHandler 源码
java
// StatementHandler 接口
public interface StatementHandler {
Statement prepare(Connection connection, Integer transactionTimeout);
void parameterize(Statement statement); // 设置参数
int update(Statement statement);
<E> List<E> query(Statement statement, ResultHandler resultHandler);
BoundSql getBoundSql();
}执行流程:
java
// SimpleExecutor.doQuery() 简化版
public <E> List<E> doQuery(MappedStatement ms, Object parameter, ...) {
// ① 创建 StatementHandler
StatementHandler handler = configuration.newStatementHandler(...);
// ② 创建 Statement(PreparedStatement/CallableStatement)
Statement stmt = prepareStatement(handler, ms.getStatementLog());
// ③ 设置参数
handler.parameterize(stmt);
// ④ 执行 SQL 并处理结果
return handler.query(stmt, resultHandler);
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) {
// 获取连接
Connection connection = getConnection(statementLog);
// 调用 prepare
Statement stmt = handler.prepare(connection, transaction.getTimeout());
// 设置参数
handler.parameterize(stmt);
return stmt;
}六、插件拦截原理
java
// Plugin.wrap() 创建代理
public static Object wrap(Object target, Interceptor interceptor) {
// 获取 @Signature 注解
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
// 获取目标类所有接口
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
// 创建 JDK 动态代理
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap)
);
}
return target;
}
// Plugin.invoke() 拦截方法调用
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断当前方法是否是需要拦截的方法
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
// 调用 Interceptor.intercept()
return interceptor.intercept(new Invocation(target, method, args));
}
// 不是拦截的方法,直接调用
return method.invoke(target, args);
}责任链包装过程:
Configuration.newExecutor()
→ executor = new SimpleExecutor() // 创建原始 Executor
→ executor = (Executor) interceptorChain.pluginAll(executor)
→ 遍历所有插件,逐层包装
→ executor = Plugin.wrap(executor, interceptor1)
→ executor = Plugin.wrap(executor, interceptor2)
→ ...
最终得到的是一个多层代理对象:
Plugin2 → Plugin1 → SimpleExecutor七、核心类关系图
SqlSessionFactory
└── creates → SqlSession
├── getMapper() → MapperProxy(动态代理)
└── delegates to → Executor
├── CachingExecutor(二级缓存)
└── delegates to → BaseExecutor(一级缓存)
├── SimpleExecutor
├── ReuseExecutor
└── BatchExecutor
└── uses → StatementHandler
├── SimpleStatementHandler
├── PreparedStatementHandler
└── CallableStatementHandler
├── ParameterHandler(参数处理)
└── ResultSetHandler(结果处理)八、速记总结
源码核心流程:
配置文件解析 → Configuration → SqlSessionFactory
→ SqlSession → Executor → StatementHandler → JDBC
Mapper 代理:JDK 动态代理 → MapperProxy → MapperMethod → SqlSession
缓存:CachingExecutor(二级)→ BaseExecutor(一级)
插件:Plugin.wrap() 创建层层代理
速记口诀:
解析配置建工厂,会话执行委托器,
Mapper 代理拦截调,缓存两层查执行,
插件层层包装类,StatementHandler 真干活。九、面试要点
| 问题 | 答案要点 |
|---|---|
| Mapper 怎么不写实现类就能执行? | JDK 动态代理,MapperProxy 拦截方法调用 |
| 一级缓存存在哪? | BaseExecutor 的 localCache(PerpetualCache) |
| 插件链怎么实现的? | 责任链模式,Plugin.wrap() 层层代理 |
| Executor 的执行流程? | Executor → StatementHandler → ParameterHandler → JDBC → ResultSetHandler |
