MyBatis MapperRegistry 的作用是什么? 它是如何管理 Mapper 接口的?

MapperRegistry 的核心作用是 管理和维护已注册的 Mapper 接口。 可以将 MapperRegistry 理解为 MyBatis 中 Mapper 接口的注册中心Mapper 接口的仓库

MapperRegistry 的核心作用概括:

MapperRegistry 的主要作用是 跟踪和管理所有已注册的 Mapper 接口,并提供根据 Mapper 接口获取 Mapper 代理对象的能力。 它确保 MyBatis 能够正确地将 Mapper 接口与对应的 SQL 映射配置关联起来,并在运行时为 Mapper 接口创建代理对象,使得开发者可以通过调用 Mapper 接口方法来执行 SQL 操作。

更详细的解释和作用分解:

  1. 注册 Mapper 接口:

    MapperRegistry 负责 注册 所有需要被 MyBatis 管理的 Mapper 接口。 Mapper 接口的注册通常发生在 MyBatis 初始化阶段,在 XMLConfigBuilder 解析 元素时完成。 Mapper 接口可以通过以下几种方式注册到 MapperRegistry 中:

    • 通过 元素指定 Mapper 接口类:

      <mappers>
          <mapper class="com.example.mapper.UserMapper"/>
      mappers>
      

      XMLConfigBuilder 在解析到 元素时,会读取 class 属性指定的 Mapper 接口类,并将其注册到 MapperRegistry 中。

    • 通过 元素指定 Mapper 接口所在的包:

      <mappers>
          <package name="com.example.mapper"/>
      mappers>
      

      XMLConfigBuilder 在解析到 元素时,会扫描 name 属性指定的包下的所有接口,并将这些接口作为 Mapper 接口注册到 MapperRegistry 中。

    • 通过 Java 代码配置 (使用 Configuration 对象):

      Configuration configuration = new Configuration();
      configuration.addMapper(UserMapper.class); // 注册单个 Mapper 接口
      configuration.addMappers("com.example.mapper"); // 注册包下所有 Mapper 接口
      

      可以使用 Configuration 对象的 addMapper(Class type)addMappers(String packageName) 方法,通过 Java 代码显式地注册 Mapper 接口。 这些方法内部最终也会将 Mapper 接口注册到 MapperRegistry 中。

  2. 存储 Mapper 接口信息:

    MapperRegistry 内部使用 Map, MapperProxyFactory> 数据结构来存储已注册的 Mapper 接口信息。

    • Key (Class): Mapper 接口的 Class 对象。 例如 UserMapper.class
    • Value (MapperProxyFactory): MapperProxyFactory 对象。 MapperProxyFactory 是一个工厂类,负责为 Mapper 接口 创建代理对象。 每个 Mapper 接口在 MapperRegistry 中都对应一个 MapperProxyFactory 实例。

    MapperRegistry 使用 Map 存储 Mapper 接口,使得可以 根据 Mapper 接口的 Class 对象快速查找和获取对应的 MapperProxyFactory

  3. 获取 Mapper 接口代理对象:

    MapperRegistry 提供了 getMapper(Class type, SqlSession sqlSession) 方法,用于 根据 Mapper 接口类型 (Class type) 和 SqlSession 实例,获取 Mapper 接口的代理对象。

    SqlSession sqlSession = ...; // 获取 SqlSession 实例
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 通过 SqlSession 获取 UserMapper 接口的代理对象
    

    SqlSession.getMapper(Class type) 方法内部会 委托给 MapperRegistrygetMapper() 方法 来获取 Mapper 代理对象。 MapperRegistry.getMapper() 方法的执行流程如下:

    • 根据 Mapper 接口类型 (Class type),从内部的 Map 中查找对应的 MapperProxyFactory
    • 如果找不到 MapperProxyFactory,表示该 Mapper 接口没有被注册,抛出 BindingException 异常。
    • 如果找到了 MapperProxyFactory,调用 MapperProxyFactory.newInstance(SqlSession sqlSession) 方法,创建 Mapper 接口的代理对象。
    • 返回创建的 Mapper 代理对象。

    MapperProxyFactory 负责创建 Mapper 接口的代理对象。 MyBatis 使用 JDK 动态代理或 CGLIB 动态代理 (取决于配置和环境) 来生成 Mapper 接口的代理对象。 代理对象会 拦截对 Mapper 接口方法的调用,并将方法调用委托给 SqlSession 的相应方法 (例如 selectList, selectOne, insert, update, delete 等) 来执行 SQL 操作。

  4. 管理 Mapper 接口和 SQL 映射的关联:

    MapperRegistry 虽然本身不直接存储 SQL 映射配置 ( MappedStatement, ResultMap 等信息存储在 Configuration 对象中),但它 通过 MapperProxyFactory 间接地管理 Mapper 接口和 SQL 映射之间的关联关系。

    • MapperProxyFactory 在创建 Mapper 代理对象时,会持有 SqlSession 实例。
    • Mapper 代理对象在拦截 Mapper 接口方法调用时,会通过 SqlSession 实例,根据 Mapper 接口方法名和 Mapper 接口命名空间,查找对应的 MappedStatement 对象 (SQL 映射)。 查找过程会委托给 Configuration 对象的 getMappedStatement() 方法。
    • 找到 MappedStatement 后,SqlSession 会使用 Executor 执行 MappedStatement 中定义的 SQL 语句,并进行参数绑定和结果映射。

    通过 MapperRegistryMapperProxyFactory 的协同工作,MyBatis 实现了 Mapper 接口和 SQL 映射的动态绑定,使得开发者可以通过面向接口的方式进行数据库操作,而无需手动编写 SQL 执行代码。

总结 MapperRegistry 的作用:

  • 注册 Mapper 接口: 负责注册 MyBatis 应用中需要管理的 Mapper 接口。
  • 存储 Mapper 接口信息: 使用 Map 存储 Mapper 接口和对应的 MapperProxyFactory
  • 获取 Mapper 代理对象: 提供 getMapper() 方法,根据 Mapper 接口类型和 SqlSession 实例,获取 Mapper 接口的代理对象。
  • 管理 Mapper 接口和 SQL 映射的关联 (间接): 通过 MapperProxyFactory,间接管理 Mapper 接口和 SQL 映射之间的关联关系,实现动态绑定。
  • 为 MyBatis 的面向接口编程提供基础: MapperRegistry 是 MyBatis 面向接口编程的核心组件,使得开发者可以通过调用 Mapper 接口方法来执行数据库操作。

简单比喻:

你可以将 MapperRegistry 比喻成一个 Mapper 接口的注册中心人才中介

  • 注册中心/人才中介 (MapperRegistry): 负责登记和管理所有注册的 Mapper 接口 (人才)。
  • Mapper 接口 (人才): 代表了数据库操作的能力接口。
  • getMapper() 方法 (获取人才): 根据 Mapper 接口类型 (人才类型),从注册中心获取对应的 Mapper 代理对象 (人才代理)。
  • MapperProxyFactory (人才代理工厂): 负责创建 Mapper 接口的代理对象 (人才代理)。 代理对象会负责实际的数据库操作 (执行工作)。

MapperRegistry 就像一个人才中介,它管理着所有注册的 Mapper 接口 (人才),并能够根据需要,为开发者提供 Mapper 接口的代理对象 (人才代理),让开发者可以通过操作代理对象来间接执行数据库操作 (管理人才来完成工作)。

你可能感兴趣的:(Mybatis,源码系列,2025,Java面试系列,mybatis)