MyBatis通过JDK动态代理在运行时生成Mapper接口的代理对象,而非编译期或字节码工具生成实现类;调用getMapper()返回Proxy实例,由MapperProxy拦截方法并委托MapperMethod执行SQL。

MyBatis 的 Mapper 接口实现类并不是在编译期生成的,也不是通过 Javassist 或 ByteBuddy 等字节码工具动态创建具体 class 文件,而是利用 JDK 动态代理(java.lang.reflect.Proxy)在运行时为每个 Mapper 接口生成一个代理对象——这个对象实现了接口,但内部不包含真实方法逻辑,所有方法调用都被统一拦截并委托给 MapperMethod 执行。
核心机制:JDK 动态代理 + MapperProxy
当你调用 sqlSession.getMapper(UserMapper.class) 时,MyBatis 实际返回的是一个由 Proxy.newProxyInstance() 创建的代理对象,其 InvocationHandler 是 MapperProxy 的实例。
-
代理目标:Mapper 接口(如
UserMapper),本身无实现类 -
处理器:
MapperProxy拦截所有接口方法调用,根据方法签名查找对应的MapperMethod -
执行中枢:
MapperMethod封装了 SQL 类型(SELECT/INSERT…)、参数处理逻辑、结果映射规则等,真正驱动 SQL 执行和结果转换
MapperProxy 如何处理方法调用
每次调用 userMapper.selectById(123),MapperProxy.invoke() 被触发:
- 从
MapperRegistry中根据接口类型和方法名,获取已解析好的MapperMethod对象(首次调用时解析 XML 或注解,缓存复用) - 调用
mapperMethod.execute(sqlSession, args),内部根据 SQL 类型分发:查询走executeForMany/executeForOne,更新走executeUpdate - 参数通过
ParamNameResolver绑定,SQL 语句由BoundSql封装,结果由ResultSetHandler映射
为什么没有生成 .class 文件?和 MyBatis-Plus 的 AutoGenerator 不同
注意区分两个概念:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
立即学习“Java免费学习笔记(深入)”;
- 运行时代理(MyBatis 原生):纯内存代理对象,无磁盘 class 文件,依赖 JDK 反射机制,轻量且启动快
-
代码生成(如 MyBatis-Plus 的
AutoGenerator或 MyBatis Generator):在开发期或构建期生成 Java 源码或 class 文件,属于静态增强,与运行时代理无关
所以 MyBatis 原生不生成任何 Mapper 实现类源码或字节码,你反编译不到 UserMapperImpl 这样的类——它根本不存在。
扩展点:可自定义代理行为
若需修改代理逻辑(如加日志、权限校验、多租户 SQL 改写),可替换默认的 MapperProxyFactory 或包装 MapperProxy:
- 继承
MapperProxyFactory,重写newInstance方法,传入自定义InvocationHandler - 在
Configuration初始化后,调用configuration.setMapperRegistry(...)注入自定义注册器 - 更常用方式是使用 MyBatis 插件(
Interceptor),在 Executor、StatementHandler 等层级拦截,无需动代理层

















