mybatis源码分析之Mapper初始化过程(1)

本文详细解析了MyBatis中Mapper的初始化过程,包括如何通过MapperRegistry的addMapper方法注册Mapper,以及MapperAnnotationBuilder的parse方法如何解析XML配置文件、缓存注解等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过分析MapperRegistry类的addMapper方法,可以看出mapper的生成过程以及初始化的机制:

public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        // 每一个mapper,创建一个MapperProxyFactory, 创建一个MapperProxyFactory用于创建自定义mapper接口的代理类
        knownMappers.put(type, new MapperProxyFactory<T>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        // 解析type的class name对于的所有的信息
        parser.parse();
        // 在末尾设一个标志位,用来判断程序是否执行到此处
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }

从源码中我们可以看出该方法中的parser.parse();的方法是生成和初始化mapper的主要入口,下面是MapperAnnotationBuilder的parse方法:

public void parse() {
    // type是mapper的class信息
    String resource = type.toString();
    if (!configuration.isResourceLoaded(resource)) {
      // 1、解析mapper的xml配置文件信息
      loadXmlResource();
      configuration.addLoadedResource(resource);
      // type.getName=xml文件中的mapper的namespace
      assistant.setCurrentNamespace(type.getName());
      // 2、解析mapper的cache注解
      parseCache();
      // 3、解析mapper中cache的引用
      parseCacheRef();
      // 4、解析mapper类型的所有的方法
      Method[] methods = type.getMethods();
      for (Method method : methods) {
        try {
          // issue #237
          if (!method.isBridge()) {
              // 解析mapper接口的方法的注解信息
            parseStatement(method);
          }
        } catch (IncompleteElementException e) {
          configuration.addIncompleteMethod(new MethodResolver(this, method));
        }
      }
    }
    parsePendingMethods();
  }

从上面的代码我们可以看出mapper初始化的步骤,其中每一步的解析过程中的部分关键源码我已经用中文进行了注释Mybatis源码中文注解

通过分析源码可以看出,如果同时在xml和mapper接口中对方法进行配置,那么接口中的注解配置会覆盖掉该方法在xml中配置。

当然在分析mapper的初始化源码的过程中,还有其他需要非常用价值的信息,后续将会继续跟进。

https://github.com/mh47838704/mybatis-3 mybatis源码中文注释版

### MyBatis 源码解析及实现原理 MyBatis 是一款优秀的持久层框架,其核心功能在于简化 JDBC 的操作流程并支持动态 SQL。以下是对其源码实现原理的深入剖析: #### 1. **MyBatis 初始化过程** MyBatis初始化主要涉及 `SqlSessionFactory` 和 `SqlSession` 对象的构建。 - 配置文件加载:通过 `SqlSessionFactoryBuilder.build()` 方法读取配置文件(如 mybatis-config.xml),完成全局设置、数据源以及 Mapper 映射文件的解析[^2]。 - 创建 `SqlSessionFactory` 实例:此实例负责管理数据库连接池和事务控制逻辑,并提供创建 `SqlSession` 的能力。 - 构建 `SqlSession`:`SqlSession` 是 MyBatis 提供的核心接口之一,它封装了执行 SQL 命令所需的所有方法。开发者可以通过 `getMapper(Class<T> type)` 获取 Mapper 接口的代理对象[^1]。 ```java // 示例代码展示如何获取 SqlSession 并调用 Mapper 方法 try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(1); } ``` --- #### 2. **Mapper 动态代理机制** 当调用 `session.getMapper(MapperInterface.class)` 时,MyBatis 使用 JDK 动态代理技术为指定的 Mapper 接口生成代理对象。具体步骤如下: - 注册 Mapper 接口:在 MyBatis 启动阶段,所有注册的 Mapper 接口会被扫描并与对应的 XML 文件或注解中的 SQL 定义建立映射关系。 - 调用拦截处理:每次调用 Mapper 接口的方法时,实际是由代理对象捕获请求并通过反射找到匹配的 SQL 执行计划。 --- #### 3. **SQL 解析与执行** MyBatis 支持多种方式定义 SQL 语句,包括基于 XML 文件和 Java 注解两种形式。无论哪种方式,最终都会被解析成统一的结构化表示。 ##### (1XML 方式的 SQL 处理 对于 `<select>` 或其他标签声明的 SQL,MyBatis 将其解析为 `MappedStatement` 对象存储于内存缓存中。其中的关键部分包括: - `id`: 表示唯一标识符; - `parameterType`: 参数类型; - `resultMap`: 结果集映射规则; - `sqlSource`: 描述 SQL 来源的信息,可能是静态字符串或是包含条件判断的动态模板[^3]。 ##### (2)注解方式的 SQL 处理 例如使用 `@Select`, `@Insert` 等注解可以直接嵌入简单的 SQL 片段。这类场景下,MyBatis 利用 `ProviderSqlSource` 进行解析并将结果转化为标准格式[^3]。 --- #### 4. **参数绑定与结果映射** - **参数绑定**:用户传递给 Mapper 方法的实际参数会经过一系列预处理后注入到最终生成的 SQL 中。特别地,如果涉及到复杂的数据结构,则可能借助 OGNL 表达式提取字段值[^3]。 - **结果映射**:查询完成后,ResultSet 数据需按照 resultMap 定义逐条组装为目标实体类的对象集合。这一环节依赖反射机制访问目标类型的 setter 方法或构造函数[^4]。 --- #### 5. **事务管理和线程安全设计** 为了保障并发环境下的一致性和隔离度要求,MyBatis 设计了一套完善的事务管理体系。默认情况下采用手动提交模式 (`autoCommit=false`) ,允许开发人员显式控制 commit/rollback 操作时间点。 同时,考虑到多线程共享同一个 Session 可能引发竞争冲突问题,官方建议遵循短生命周期原则及时关闭无用资源以释放锁占用。 --- ### 总结 通过对以上各部分内容的学习可以发现,MyBatis 不仅提供了灵活易用的功能特性,而且内部架构也极具扩展性与可维护价值。理解它的运行机理会极大提升我们在日常项目开发中的效率和技术水平! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值