整体架构
MyBatis-Plus 的核心设计是“编译式准备、运行时执行”:启动阶段准备实体元数据和通用 SQL,查询阶段只组合参数并进入 MyBatis 原生执行器。
先给答案:MyBatis-Plus 的核心设计是“编译式准备、运行时执行”:启动阶段准备实体元数据和通用 SQL,查…
Section titled “先给答案:MyBatis-Plus 的核心设计是“编译式准备、运行时执行”:启动阶段准备实体元数据和通用 SQL,查…”MyBatis-Plus 的核心设计是“编译式准备、运行时执行”:启动阶段准备实体元数据和通用 SQL,查询阶段只组合参数并进入 MyBatis 原生执行器。 正文沿“分层 -> 主流程一:启动 -> 主流程二:查询”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。
主要失效边界集中在“Mapper 泛型缺失、插件顺序错误、XML 与注入同名”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。
| 层 | 职责 | 源码坐标 |
|---|---|---|
| 配置 | 扩展 MyBatis Configuration | MybatisConfiguration.java:58-110 |
| 元数据 | 解析实体、字段、主键和策略 | TableInfoHelper.java:55-205 |
| 注入 | 生成通用 CRUD MappedStatement | AbstractMethod.java:82-120 |
| API | 暴露 Mapper、Wrapper、Service | BaseMapper.java:97-150 |
| 拦截 | 改写 BoundSql 或更新参数 | MybatisPlusInterceptor.java:50-105 |
主流程一:启动
Section titled “主流程一:启动”Spring / MyBatis bootstrap └─► mapper parsed └─► TableInfoHelper.initTableInfo └─► SqlInjector methods └─► addMappedStatement └─► Configuration mappedStatementsTableInfoHelper 从 Mapper 泛型或实体类开始初始化 TableInfo;注入器随后为 BaseMapper 派生接口添加 insert、update、delete、select 等语句。关键坐标:TableInfoHelper.java:115-205、TableInfoHelper.java:240-380、AbstractMethod.java:82-120、AbstractMethod.java:150-210、AbstractMethod.java:390-445、MybatisConfiguration.java:330-365。
主流程二:查询
Section titled “主流程二:查询”mapper.selectList(wrapper) └─► BaseMapper default method └─► mapper proxy invokes statement id └─► MybatisPlusInterceptor ├─► beforeQuery ├─► beforePrepare └─► Executor.query/updateWrapper 只负责生成条件片段和参数映射,真正的 JDBC 执行仍由 MyBatis Executor 完成。关键坐标:BaseMapper.java:180-245、AbstractWrapper.java:50-125、AbstractWrapper.java:603-680、MybatisPlusInterceptor.java:56-105、MybatisSqlSessionFactoryBean.java:600-690、ServiceImpl.java:28-30。
为什么不重写 MyBatis Executor
Section titled “为什么不重写 MyBatis Executor”替代方案:复制一套 Executor 和 Mapper 代理,直接接管 CRUD。
为什么不行:会与 MyBatis 的缓存、事务、结果映射和插件机制分叉,升级成本高。
证据:MyBatis-Plus 选择扩展 Configuration、注入 MappedStatement 和实现 MyBatis Interceptor,执行仍回到 MyBatis 原生链路。
| 场景 | 现象 | 原因 | 规避 |
|---|---|---|---|
| Mapper 泛型缺失 | 找不到实体表信息 | 无法推导 modelClass | 明确 BaseMapper<Entity> |
| 插件顺序错误 | 分页或租户 SQL 异常 | SQL 改写有先后依赖 | 按文档顺序注册 |
| XML 与注入同名 | 语句未按预期生成 | 已存在 statement 被跳过 | 避免同名或确认覆盖策略 |
框架增强既可以通过重写核心执行器实现,也可以通过元数据预计算、声明式语句注入和标准插件点实现;后者通常更容易兼容上游。
面试锚点
- MyBatis-Plus 如何生成通用 CRUD?
- TableInfo 在什么时候初始化?
- 为什么不直接替换 MyBatis Executor?