价格

架构总览

相关源文件

本页面内容基于以下源文件生成:

MyBatis-Plus 是 MyBatis 的增强工具,在 MyBatis 基础上只做增强不做改变,为简化开发、提高效率而生。该框架通过扩展 MyBatis 核心组件,实现了无侵入式的功能增强,包括通用 CRUD 操作、分页插件、性能分析等功能,同时保持了与原生 MyBatis 的完全兼容。

系统架构总览

MyBatis-Plus 采用分层架构设计,通过继承和扩展 MyBatis 原生组件实现功能增强。整体架构分为四个主要层次:配置层、会话层、映射层和注解层,各层之间通过明确的接口进行协作。

正在加载图表渲染器...

架构要点说明:

  1. 配置层MybatisConfiguration 继承自 MyBatis 原生 Configuration 类,作为整个框架的核心配置容器,管理所有 Mapper 注册、SQL 语句映射和缓存策略。内部使用 StrictMap 确保配置项的唯一性和冲突检测。

  2. 会话层MybatisSqlSessionFactoryBuilder 负责构建 SqlSessionFactory 实例,在此过程中初始化全局配置和 ID 生成器,支持雪花算法等多种 ID 生成策略。

  3. 映射层MybatisMapperRegistry 替代原生 MapperRegistry,通过动态代理机制创建 Mapper 接口实例,同时协调方法解析和 SQL 注入流程。

  4. 注解层@TableName 等注解提供实体类与数据库表之间的映射元数据,框架在启动时通过反射读取这些注解信息构建元数据模型。

核心配置体系

MybatisConfiguration 配置容器

MybatisConfiguration 是 MyBatis-Plus 的核心配置类,继承自 MyBatis 原生 Configuration 并进行了多项扩展。该类在初始化时自动开启下划线转驼峰命名策略,并将默认枚举类型处理器设置为 CompositeEnumTypeHandler

java
1public 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 负责)

关键数据结构:

数据结构类型用途
mybatisMapperRegistryMybatisMapperRegistryMapper 接口注册中心
cachesStrictMap<String, Cache>二级缓存集合
mappedStatementsStrictMap<String, MappedStatement>SQL 语句映射集合
resultMapsStrictMap<String, ResultMap>结果集映射集合

SQL 加载优先级策略:

MyBatis-Plus 定义了明确的 SQL 加载顺序,确保配置的一致性和可预测性:

  1. XML 中的 SQL:优先级最高,从 XML 配置文件加载的 SQL 语句
  2. SqlProvider 中的 SQL:通过 @SelectProvider 等注解提供的 SQL
  3. CurSql(通用 CRUD):框架自动注入的通用 CRUD SQL

当检测到重复的 SQL ID 时,框架会记录错误日志并忽略后续的重复定义,这种行为在 addMappedStatement 方法中实现:

java
1@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 严格映射集合

StrictMapMybatisConfiguration 的内部类,继承自 ConcurrentHashMap,提供了更严格的键值管理机制。该类通过 conflictMessageProducer 函数支持自定义冲突错误消息,在检测到重复键时能够提供详细的上下文信息。

关键特性:

  • 线程安全:继承 ConcurrentHashMap 的并发能力
  • 冲突检测:支持自定义冲突消息生成器
  • 严格模式:不允许键重复,重复时抛出异常或记录错误

会话工厂构建

MybatisSqlSessionFactoryBuilder 构建流程

MybatisSqlSessionFactoryBuilder 是 MyBatis-Plus 的会话工厂构建器,继承自 MyBatis 原生 SqlSessionFactoryBuilder。该类负责解析配置文件、初始化全局配置、设置 ID 生成器,最终构建 SqlSessionFactory 实例。

正在加载图表渲染器...

构建流程关键步骤:

  1. 配置解析:通过 MybatisXMLConfigBuilder 解析 XML 配置文件,构建 MybatisConfiguration 实例。参考 MybatisSqlSessionFactoryBuilder.java:48-62

  2. 全局配置获取:从 Configuration 中提取 GlobalConfig,获取框架级别的配置项。参考 MybatisSqlSessionFactoryBuilder.java:83-84

  3. ID 生成器初始化:根据配置选择合适的 ID 生成策略,支持手动配置 WorkerId/DatacenterId 或自动检测网络地址。参考 MybatisSqlSessionFactoryBuilder.java:86-105

错误处理与边界条件:

异常场景处理策略
配置文件解析失败捕获异常并包装为 ExceptionFactory.wrapException
IO 异常(关闭流)在 finally 块中捕获并有意忽略,优先保留之前的错误
网络地址检测失败回退到固定 ID 生成器,记录日志
ID 生成器未配置使用默认的雪花算法实现

InjectorResolver 注入解析器

InjectorResolver 是 MyBatis-Plus 的 SQL 注入解析器,继承自 MethodResolver。该类负责触发 Mapper 接口中的 SQL 方法注入流程,是连接 Mapper 注册和 SQL 生成的重要桥梁。

java
1public 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:

方法参数返回值用途
addMapperClass&lt;T&gt; typevoid注册 Mapper 接口
getMapperClass&lt;T&gt; type, SqlSession sqlSessionT获取 Mapper 代理实例
hasMapperClass&lt;T&gt; typeboolean检查 Mapper 是否已注册
removeMapperClass&lt;T&gt; typevoid移除已注册的 Mapper

动态代理机制:

java
1@Override
2public &lt;T&gt; T getMapper(Class&lt;T&gt; type, SqlSession sqlSession) {
3    MybatisMapperProxyFactory&lt;T&gt; mapperProxyFactory = (MybatisMapperProxyFactory&lt;T&gt;) knownMappers.get(type);
4    if (mapperProxyFactory == null) {
5        // 支持通过类名查找(兼容性处理)
6        mapperProxyFactory = (MybatisMapperProxyFactory&lt;T&gt;) 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 方法。

java
1public 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 生成逻辑。测试用例展示了该类的使用方式:

java
1static 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

参考 MethodTest.java:14-45

注解与元数据

TableName 表名映射注解

@TableName 注解用于定义实体类与数据库表之间的映射关系,支持配置表名、schema、表前缀策略以及结果集映射。

java
1@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}

配置项说明:

属性类型默认值说明
valueString""实体对应的表名,为空时使用类名
schemaString""数据库 schema,覆盖全局配置
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix
resultMapClass<?>void.class实体映射结果集

参考 TableName.java:17-56

MybatisPlusVersion 版本管理

MybatisPlusVersion 提供框架版本信息的获取能力,通过多种策略尝试获取版本号:优先从 Package 元数据获取,其次从 JAR 文件 MANIFEST 获取。

java
1public 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)统一管理版本依赖。项目包含以下核心模块:

正在加载图表渲染器...

模块依赖关系说明:

  1. mybatis-plus-bom:作为 BOM 模块,统一管理所有子模块的版本号,确保依赖一致性。参考 mybatis-plus-bom/build.gradle:1-28

  2. mybatis-plus(聚合模块):聚合核心模块,对外提供统一的依赖入口。参考 mybatis-plus/build.gradle:2-41

  3. mybatis-plus-core:核心实现模块,包含配置、会话、映射等核心功能。

  4. mybatis-plus-annotation:注解定义模块,包含所有框架注解。

  5. mybatis-plus-spring:Spring 集成模块,提供与 Spring 框架的集成能力。

构建配置要点

根项目的 build.gradle 定义了通用的构建任务和发布配置:

Java 编译配置:

groovy
1tasks.withType(JavaCompile) {
2    options.encoding = 'UTF-8'
3    options.warnings = false
4    options.deprecation = true
5    options.compilerArgs += ["-parameters"]  // 保留参数名信息
6}

JAR 包元数据:

groovy
1manifest {
2    attributes 'Implementation-Title': archiveBaseName
3    attributes 'Implementation-Version': archiveVersion
4    attributes 'Automatic-Module-Name': "${project.group}.${project.name.replaceAll("-", ".")}"
5}

参考 build.gradle:110-242

核心设计决策与取舍

1. 继承扩展而非组合包装

决策:MyBatis-Plus 选择继承 MyBatis 原生类(如 ConfigurationSqlSessionFactoryBuilder)而非组合包装。

理由

  • 保持与原生 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

技术选型

技术/组件用途选型理由替代方案
MyBatisORM 框架基础市场占有率高、SQL 控制力强Hibernate、JPA
Gradle构建工具灵活性高、支持多模块构建Maven
JUnit 5单元测试现代化测试框架、参数化测试支持JUnit 4、TestNG
Kotlin扩展语言与 Java 互操作性好、简洁Groovy、Scala
JSqlParserSQL 解析解析能力强、支持多种数据库Druid SQL Parser
Spring Boot集成框架自动配置、开箱即用Spring Framework
Snowflake 算法ID 生成分布式唯一、时间有序UUID、数据库序列
动态代理Mapper 实例化JDK 原生支持、性能可接受CGLIB、ByteBuddy
ConcurrentHashMap并发存储线程安全、高性能synchronized Map
注解反射元数据读取运行时获取配置信息XML 配置

关键配置与启动流程

启动流程概览

正在加载图表渲染器...

核心配置项

MybatisConfiguration 初始化配置:

配置项默认值说明
mapUnderscoreToCamelCasetrue自动映射下划线到驼峰
typeHandlerRegistry.defaultEnumTypeHandlerCompositeEnumTypeHandler默认枚举类型处理器
languageRegistry.defaultDriverClassMybatisXMLLanguageDriver默认语言驱动
useGeneratedShortKeytrue是否生成短 key 缓存

参考 MybatisConfiguration.java:90-95

GlobalConfig 全局配置:

配置项说明
identifierGeneratorID 生成器实例
sequence.workerId雪花算法工作节点 ID
sequence.datacenterId雪花算法数据中心 ID
sequence.preferredNetworks优先网络地址列表
sequence.ignoredInterfaces忽略的网络接口列表

参考 MybatisSqlSessionFactoryBuilder.java:86-101

Mapper 注册流程

  1. 接口检查:验证注册的类型是否为接口
  2. 重复检查:检查 Mapper 是否已注册,避免重复注册
  3. 创建代理工厂:为 Mapper 接口创建 MybatisMapperProxyFactory
  4. 注解解析:解析 Mapper 接口上的注解信息
  5. SQL 注入:根据注解和实体类信息注入通用 SQL

参考 MybatisMapperRegistry.java:77-87