架构总览
相关源文件
本页面内容基于以下源文件生成:
- mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisConfiguration.java
- mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisSqlSessionFactoryBuilder.java
- mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisMapperRegistry.java
- mybatis-plus-annotation/src/main/java/com/baomidou/mybatisplus/annotation/TableName.java
- settings.gradle
- mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/MethodTest.java
- mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/package-info.java
- mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/InjectorResolver.java
- mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisPlusVersion.java
- mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisMethodResolver.java
- build.gradle
- mybatis-plus/build.gradle
- mybatis-plus-bom/build.gradle
- mybatis-plus-core/build.gradle
- mybatis-plus-spring/build.gradle
- spring-boot-starter/build.gradle
- mybatis-plus-extension/build.gradle
- mybatis-plus-generator/build.gradle
- mybatis-plus-annotation/build.gradle
- mybatis-plus-jsqlparser-support/build.gradle
MyBatis-Plus 是 MyBatis 的增强工具,在 MyBatis 基础上只做增强不做改变,为简化开发、提高效率而生。该框架通过扩展 MyBatis 核心组件,实现了无侵入式的功能增强,包括通用 CRUD 操作、分页插件、性能分析等功能,同时保持了与原生 MyBatis 的完全兼容。
系统架构总览
MyBatis-Plus 采用分层架构设计,通过继承和扩展 MyBatis 原生组件实现功能增强。整体架构分为四个主要层次:配置层、会话层、映射层和注解层,各层之间通过明确的接口进行协作。
正在加载图表渲染器...
架构要点说明:
-
配置层:MybatisConfiguration 继承自 MyBatis 原生
Configuration类,作为整个框架的核心配置容器,管理所有 Mapper 注册、SQL 语句映射和缓存策略。内部使用 StrictMap 确保配置项的唯一性和冲突检测。 -
会话层:MybatisSqlSessionFactoryBuilder 负责构建
SqlSessionFactory实例,在此过程中初始化全局配置和 ID 生成器,支持雪花算法等多种 ID 生成策略。 -
映射层:MybatisMapperRegistry 替代原生
MapperRegistry,通过动态代理机制创建 Mapper 接口实例,同时协调方法解析和 SQL 注入流程。 -
注解层:@TableName 等注解提供实体类与数据库表之间的映射元数据,框架在启动时通过反射读取这些注解信息构建元数据模型。
核心配置体系
MybatisConfiguration 配置容器
MybatisConfiguration 是 MyBatis-Plus 的核心配置类,继承自 MyBatis 原生 Configuration 并进行了多项扩展。该类在初始化时自动开启下划线转驼峰命名策略,并将默认枚举类型处理器设置为 CompositeEnumTypeHandler。
java1public class MybatisConfiguration extends Configuration { 2 protected final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this); 3 protected final Map<String, Cache> caches = new StrictMap<>("Caches collection"); 4 protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection") 5 .conflictMessageProducer((savedValue, targetValue) -> 6 ". please check " + savedValue.getResource() + " and " + targetValue.getResource()); 7}
职责边界:
- 负责:管理 MyBatis-Plus 的所有配置项、Mapper 注册、SQL 语句存储、缓存管理
- 不负责:数据库连接管理(由
Environment负责)、事务管理(由TransactionFactory负责)
关键数据结构:
| 数据结构 | 类型 | 用途 |
|---|---|---|
mybatisMapperRegistry | MybatisMapperRegistry | Mapper 接口注册中心 |
caches | StrictMap<String, Cache> | 二级缓存集合 |
mappedStatements | StrictMap<String, MappedStatement> | SQL 语句映射集合 |
resultMaps | StrictMap<String, ResultMap> | 结果集映射集合 |
SQL 加载优先级策略:
MyBatis-Plus 定义了明确的 SQL 加载顺序,确保配置的一致性和可预测性:
- XML 中的 SQL:优先级最高,从 XML 配置文件加载的 SQL 语句
- SqlProvider 中的 SQL:通过
@SelectProvider等注解提供的 SQL - CurSql(通用 CRUD):框架自动注入的通用 CRUD SQL
当检测到重复的 SQL ID 时,框架会记录错误日志并忽略后续的重复定义,这种行为在 addMappedStatement 方法中实现:
java1@Override 2public void addMappedStatement(MappedStatement ms) { 3 if (mappedStatements.containsKey(ms.getId())) { 4 logger.error("mapper[" + ms.getId() + "] is ignored, because it exists, maybe from xml file"); 5 return; 6 } 7 mappedStatements.put(ms.getId(), ms); 8}
StrictMap 严格映射集合
StrictMap 是 MybatisConfiguration 的内部类,继承自 ConcurrentHashMap,提供了更严格的键值管理机制。该类通过 conflictMessageProducer 函数支持自定义冲突错误消息,在检测到重复键时能够提供详细的上下文信息。
关键特性:
- 线程安全:继承
ConcurrentHashMap的并发能力 - 冲突检测:支持自定义冲突消息生成器
- 严格模式:不允许键重复,重复时抛出异常或记录错误
会话工厂构建
MybatisSqlSessionFactoryBuilder 构建流程
MybatisSqlSessionFactoryBuilder 是 MyBatis-Plus 的会话工厂构建器,继承自 MyBatis 原生 SqlSessionFactoryBuilder。该类负责解析配置文件、初始化全局配置、设置 ID 生成器,最终构建 SqlSessionFactory 实例。
正在加载图表渲染器...
构建流程关键步骤:
-
配置解析:通过
MybatisXMLConfigBuilder解析 XML 配置文件,构建MybatisConfiguration实例。参考 MybatisSqlSessionFactoryBuilder.java:48-62 -
全局配置获取:从
Configuration中提取GlobalConfig,获取框架级别的配置项。参考 MybatisSqlSessionFactoryBuilder.java:83-84 -
ID 生成器初始化:根据配置选择合适的 ID 生成策略,支持手动配置 WorkerId/DatacenterId 或自动检测网络地址。参考 MybatisSqlSessionFactoryBuilder.java:86-105
错误处理与边界条件:
| 异常场景 | 处理策略 |
|---|---|
| 配置文件解析失败 | 捕获异常并包装为 ExceptionFactory.wrapException |
| IO 异常(关闭流) | 在 finally 块中捕获并有意忽略,优先保留之前的错误 |
| 网络地址检测失败 | 回退到固定 ID 生成器,记录日志 |
| ID 生成器未配置 | 使用默认的雪花算法实现 |
InjectorResolver 注入解析器
InjectorResolver 是 MyBatis-Plus 的 SQL 注入解析器,继承自 MethodResolver。该类负责触发 Mapper 接口中的 SQL 方法注入流程,是连接 Mapper 注册和 SQL 生成的重要桥梁。
java1public class InjectorResolver extends MethodResolver { 2 private final MybatisMapperAnnotationBuilder annotationBuilder; 3 4 public InjectorResolver(MybatisMapperAnnotationBuilder annotationBuilder) { 5 super(annotationBuilder, null); 6 this.annotationBuilder = annotationBuilder; 7 } 8 9 @Override 10 public void resolve() { 11 annotationBuilder.parserInjector(); 12 } 13}
职责边界:
- 负责:触发 SQL 注入流程、协调注解解析器
- 不负责:具体的 SQL 生成逻辑(由
AbstractMethod子类负责)
参考 InjectorResolver.java:26-39
方法解析与注入
MybatisMapperRegistry 注册中心
MybatisMapperRegistry 是 MyBatis-Plus 自定义的 Mapper 注册中心,替代了 MyBatis 原生的 MapperRegistry。该类使用 ConcurrentHashMap 存储已注册的 Mapper 接口及其对应的代理工厂,支持并发访问和动态注册。
核心 API:
| 方法 | 参数 | 返回值 | 用途 |
|---|---|---|---|
addMapper | Class<T> type | void | 注册 Mapper 接口 |
getMapper | Class<T> type, SqlSession sqlSession | T | 获取 Mapper 代理实例 |
hasMapper | Class<T> type | boolean | 检查 Mapper 是否已注册 |
removeMapper | Class<T> type | void | 移除已注册的 Mapper |
动态代理机制:
java1@Override 2public <T> T getMapper(Class<T> type, SqlSession sqlSession) { 3 MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.get(type); 4 if (mapperProxyFactory == null) { 5 // 支持通过类名查找(兼容性处理) 6 mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.entrySet().stream() 7 .filter(t -> t.getKey().getName().equals(type.getName())).findFirst().map(Map.Entry::getValue) 8 .orElseThrow(() -> new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry.")); 9 } 10 return mapperProxyFactory.newInstance(sqlSession); 11}
参考 MybatisMapperRegistry.java:46-61
错误处理:
- Mapper 未找到:抛出
BindingException,提示类型未注册 - 代理实例创建失败:捕获异常并包装为
BindingException
MybatisMethodResolver 方法解析器
MybatisMethodResolver 负责将 Mapper 接口中的方法解析为可执行的 SQL 语句。该类持有 MybatisMapperAnnotationBuilder 引用和 Method 对象,在解析时调用注解构建器的 parseStatement 方法。
java1public class MybatisMethodResolver extends MethodResolver { 2 private final MybatisMapperAnnotationBuilder annotationBuilder; 3 private final Method method; 4 5 public MybatisMethodResolver(MybatisMapperAnnotationBuilder annotationBuilder, Method method) { 6 super(null, null); 7 this.annotationBuilder = annotationBuilder; 8 this.method = method; 9 } 10 11 @Override 12 public void resolve() { 13 annotationBuilder.parseStatement(method); 14 } 15}
参考 MybatisMethodResolver.java:28-43
AbstractMethod 抽象方法层
AbstractMethod 是所有 SQL 注入方法的抽象基类,定义了 injectMappedStatement 抽象方法,由具体的子类实现不同类型的 SQL 生成逻辑。测试用例展示了该类的使用方式:
java1static class TestMethod extends AbstractMethod { 2 public TestMethod(String methodName) { 3 super(methodName); 4 } 5 6 @Override 7 public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { 8 return null; // 具体实现由子类提供 9 } 10}
内置方法实现:
| 方法类 | 功能 | SQL 类型 |
|---|---|---|
Insert | 插入数据 | INSERT |
Delete | 删除数据 | DELETE |
Update | 更新数据 | UPDATE |
SelectPage | 分页查询 | SELECT |
注解与元数据
TableName 表名映射注解
@TableName 注解用于定义实体类与数据库表之间的映射关系,支持配置表名、schema、表前缀策略以及结果集映射。
java1@Documented 2@Retention(RetentionPolicy.RUNTIME) 3@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) 4public @interface TableName { 5 String value() default ""; // 表名 6 String schema() default ""; // schema 7 boolean keepGlobalPrefix() default false; // 是否保持全局表前缀 8 Class<?> resultMap() default void.class; // 结果集映射 9}
配置项说明:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value | String | "" | 实体对应的表名,为空时使用类名 |
schema | String | "" | 数据库 schema,覆盖全局配置 |
keepGlobalPrefix | boolean | false | 是否保持使用全局的 tablePrefix |
resultMap | Class<?> | void.class | 实体映射结果集 |
MybatisPlusVersion 版本管理
MybatisPlusVersion 提供框架版本信息的获取能力,通过多种策略尝试获取版本号:优先从 Package 元数据获取,其次从 JAR 文件 MANIFEST 获取。
java1public class MybatisPlusVersion { 2 public static String getVersion() { 3 return determineSpringBootVersion(); 4 } 5 6 private static String determineSpringBootVersion() { 7 final Package pkg = MybatisPlusVersion.class.getPackage(); 8 if (pkg != null && pkg.getImplementationVersion() != null) { 9 return pkg.getImplementationVersion(); 10 } 11 // 从 JAR 文件 MANIFEST 获取版本 12 // ... 13 } 14}
参考 MybatisPlusVersion.java:32-68
模块组织结构
多模块架构
MyBatis-Plus 采用 Gradle 多模块架构,通过 BOM(Bill of Materials)统一管理版本依赖。项目包含以下核心模块:
正在加载图表渲染器...
模块依赖关系说明:
-
mybatis-plus-bom:作为 BOM 模块,统一管理所有子模块的版本号,确保依赖一致性。参考 mybatis-plus-bom/build.gradle:1-28
-
mybatis-plus(聚合模块):聚合核心模块,对外提供统一的依赖入口。参考 mybatis-plus/build.gradle:2-41
-
mybatis-plus-core:核心实现模块,包含配置、会话、映射等核心功能。
-
mybatis-plus-annotation:注解定义模块,包含所有框架注解。
-
mybatis-plus-spring:Spring 集成模块,提供与 Spring 框架的集成能力。
构建配置要点
根项目的 build.gradle 定义了通用的构建任务和发布配置:
Java 编译配置:
groovy1tasks.withType(JavaCompile) { 2 options.encoding = 'UTF-8' 3 options.warnings = false 4 options.deprecation = true 5 options.compilerArgs += ["-parameters"] // 保留参数名信息 6}
JAR 包元数据:
groovy1manifest { 2 attributes 'Implementation-Title': archiveBaseName 3 attributes 'Implementation-Version': archiveVersion 4 attributes 'Automatic-Module-Name': "${project.group}.${project.name.replaceAll("-", ".")}" 5}
核心设计决策与取舍
1. 继承扩展而非组合包装
决策:MyBatis-Plus 选择继承 MyBatis 原生类(如 Configuration、SqlSessionFactoryBuilder)而非组合包装。
理由:
- 保持与原生 MyBatis API 的完全兼容
- 减少代理层带来的性能开销
- 简化框架集成复杂度
限制:
- 受限于 MyBatis 原生类的继承体系
- 需要关注上游版本变更的影响
2. SQL 加载优先级策略
决策:定义明确的 SQL 加载优先级:XML > SqlProvider > CrudSql。
理由:
- XML 配置具有最高优先级,便于 DBA 审查和优化 SQL
- SqlProvider 提供动态 SQL 能力
- CrudSql 作为兜底,提供通用操作
实现:通过 StrictMap 的冲突检测机制确保优先级执行。参考 MybatisConfiguration.java:105-114
3. 动态代理工厂模式
决策:使用 MybatisMapperProxyFactory 创建 Mapper 接口的动态代理实例。
理由:
- 延迟初始化,减少启动时开销
- 支持运行时动态增强
- 与 MyBatis 原生机制保持一致
关键实现:参考 MybatisMapperRegistry.java:50-57
4. 多策略 ID 生成
决策:支持多种 ID 生成策略,包括手动配置和自动检测。
理由:
- 适应不同的部署环境(单机、集群、云原生)
- 雪花算法提供分布式唯一性保证
- 自动检测降低配置复杂度
边界处理:网络地址检测失败时回退到固定 ID 生成器。参考 MybatisSqlSessionFactoryBuilder.java:92-99
5. 严格映射集合
决策:使用 StrictMap 替代普通的 Map 存储配置项。
理由:
- 早期发现配置冲突
- 提供详细的错误上下文
- 确保配置的唯一性和一致性
实现:通过 conflictMessageProducer 支持自定义错误消息。参考 MybatisConfiguration.java:409-447
技术选型
| 技术/组件 | 用途 | 选型理由 | 替代方案 |
|---|---|---|---|
| MyBatis | ORM 框架基础 | 市场占有率高、SQL 控制力强 | Hibernate、JPA |
| Gradle | 构建工具 | 灵活性高、支持多模块构建 | Maven |
| JUnit 5 | 单元测试 | 现代化测试框架、参数化测试支持 | JUnit 4、TestNG |
| Kotlin | 扩展语言 | 与 Java 互操作性好、简洁 | Groovy、Scala |
| JSqlParser | SQL 解析 | 解析能力强、支持多种数据库 | Druid SQL Parser |
| Spring Boot | 集成框架 | 自动配置、开箱即用 | Spring Framework |
| Snowflake 算法 | ID 生成 | 分布式唯一、时间有序 | UUID、数据库序列 |
| 动态代理 | Mapper 实例化 | JDK 原生支持、性能可接受 | CGLIB、ByteBuddy |
| ConcurrentHashMap | 并发存储 | 线程安全、高性能 | synchronized Map |
| 注解反射 | 元数据读取 | 运行时获取配置信息 | XML 配置 |
关键配置与启动流程
启动流程概览
正在加载图表渲染器...
核心配置项
MybatisConfiguration 初始化配置:
| 配置项 | 默认值 | 说明 |
|---|---|---|
mapUnderscoreToCamelCase | true | 自动映射下划线到驼峰 |
typeHandlerRegistry.defaultEnumTypeHandler | CompositeEnumTypeHandler | 默认枚举类型处理器 |
languageRegistry.defaultDriverClass | MybatisXMLLanguageDriver | 默认语言驱动 |
useGeneratedShortKey | true | 是否生成短 key 缓存 |
参考 MybatisConfiguration.java:90-95
GlobalConfig 全局配置:
| 配置项 | 说明 |
|---|---|
identifierGenerator | ID 生成器实例 |
sequence.workerId | 雪花算法工作节点 ID |
sequence.datacenterId | 雪花算法数据中心 ID |
sequence.preferredNetworks | 优先网络地址列表 |
sequence.ignoredInterfaces | 忽略的网络接口列表 |
参考 MybatisSqlSessionFactoryBuilder.java:86-101
Mapper 注册流程
- 接口检查:验证注册的类型是否为接口
- 重复检查:检查 Mapper 是否已注册,避免重复注册
- 创建代理工厂:为 Mapper 接口创建
MybatisMapperProxyFactory - 注解解析:解析 Mapper 接口上的注解信息
- SQL 注入:根据注解和实体类信息注入通用 SQL
