【MyBatis源码】SqlSession执行Mapper过程

🎮 作者主页:点击

🎁 完整专栏和代码:点击

🏡 博客主页:点击

文章目录

  • Mapper接口的注册过程
  • [knownMappers使用 MapperProxyFactory 而不是直接存储代理类原因分析](#knownMappers使用 MapperProxyFactory 而不是直接存储代理类原因分析)

Mapper接口的注册过程

Mapper接口用于定义执行SQL语句相关的方法,方法名一般和Mapper XML配置文件中<select|update|delete|insert>标签的id属性相同,接口的完全限定名一般对应Mapper XML配置文件的命名空间。

java 复制代码
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    UserBean res = mapper.selectDataById(1);
java 复制代码
  @Select("select * from t_user where id=#{id}")
  @Result(column = "jsonInfo", property = "jsonInfo", typeHandler = JsonTypeHandler.class)
  UserBean selectDataById(int id);

在上面的代码中我们通过sqlSession.getMapper(UserMapper.class);就可以执行对应的SQL语句,但是这只是一个接口,我们并没有提供对应的实现类,那么这个是如何实现的呢?

实际上getMapper()方法返回的是一个动态代理对象。MyBatis中通过MapperProxy类实现动态代理。

MyBatis框架在应用启动时会解析所有的Mapper接口,然后调用MapperRegistry对象的addMapper()方法将Mapper接口信息和对应的MapperProxyFactory对象注册到MapperRegistry对象中。

knownMappers使用 MapperProxyFactory 而不是直接存储代理类原因分析

java 复制代码
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);

knownMappers 是一个 Map<Class<?>, MapperProxyFactory<?>> 类型的成员变量,表示的是 Mapper 类型与其对应的 MapperProxyFactory 对象的映射。

在 MyBatis 的启动过程中,当 MyBatis 扫描到一个新的 Mapper 接口时,它会通过 MapperRegistry 的 addMapper() 方法将该接口及其对应的 MapperProxyFactory 对象注册到 knownMappers 中

为什么knownMappers使用 MapperProxyFactory 而不是直接存储代理类呢?

在 MyBatis 中使用 MapperProxyFactory 而不是直接存储代理类,背后的设计原因和原理主要与 灵活性 和 延迟加载(懒加载)有关。以下是为什么选择 MapperProxyFactory 而不是直接存储代理类的几个关键原因:

【1】 代理类的创建开销:如果在 addMapper 时就直接将代理类实例化并存入 knownMappers 中,这意味着每次添加 Mapper 时都会实例化一个代理对象,这在某些情况下是不必要的,尤其是在大规模的应用程序中,可能会增加性能负担。

【2】 懒加载机制:MapperProxyFactory 作为一个工厂类,它只会在调用 getMapper() 时,针对某个特定的 Mapper接口动态创建代理实例。这样,代理对象只会在需要时创建,避免了在启动时就为每个 Mapper 创建一个代理对象的开销。

【3】 设计原理:这种懒加载的设计方式使得 MyBatis 更加高效。只有在需要对某个 Mapper 进行操作时,才会创建相应的代理对象,避免了不必要的对象创建和内存占用。

【4】 代理类与接口分离:MapperProxyFactory 是一个工厂类,负责根据 Mapper 接口创建代理对象。通过工厂模式,MyBatis 可以灵活地控制何时创建代理类,并且保持代码的解耦性。如果直接存储代理实例,则每次获取时只能使用已创建的代理,无法实现这种灵活的控制。

【5】 工厂模式的好处:使用工厂模式可以让我们在运行时动态地创建不同类型的代理。例如,在不同的环境下,代理对象可能具有不同的行为,或者在某些情况下需要特殊的处理,MapperProxyFactory 可以灵活地根据这些需求创建代理对象。

【6】 控制代理对象的创建:如果直接将代理对象存储在 knownMappers 中,那么在获取 Mapper 时就无法控制代理的创建和配置。而通过工厂模式,MyBatis 可以在创建代理对象时加入一些额外的逻辑,比如事务处理、拦截器等。

【7】 避免多次创建相同的代理:MapperProxyFactory 是通过 newInstance 方法来创建代理对象的,每次调用 getMapper() 方法时,MapperProxyFactory 都会根据当前的 SqlSession 创建一个新的代理实例。而如果直接将代理对象存储在 knownMappers 中,那么每次访问都会返回相同的代理对象,这可能导致一些问题(如会话状态不一致)。通过每次调用 getMapper 创建新的代理对象,MyBatis 可以确保每个 SqlSession 使用的是独立的代理实例,避免不同的会话之间共享相同的代理对象,从而保持隔离性。

【8】 可扩展性。在 MyBatis 中,代理对象可能会涉及到一些额外的逻辑,比如事务管理、缓存管理、日志记录等。这些逻辑通常通过插件或者拦截器的方式进行处理,而 MapperProxyFactory 可以灵活地插入这些处理逻辑。如果直接将代理对象存入 knownMappers,则无法在代理对象创建时灵活地添加这些额外的功能。如果直接存储代理对象,意味着所有的代理类都会被硬编码在 MapperRegistry 中,这不利于框架的灵活扩展。而通过 MapperProxyFactory,MyBatis 可以根据不同的需求创建不同的代理,保持系统的灵活性和可扩展性。

【9】 工厂模式统一管理代理类的创建:MapperProxyFactory 作为一个工厂类,它为每个 Mapper 类型提供了统一的创建代理对象的接口。通过这种方式,MyBatis 可以更清晰地管理不同 Mapper 接口的代理对象,而不需要为每个接口单独处理创建逻辑。

相关推荐
迷枫71239 分钟前
SQL性能排查记录
java·数据库·sql
渡我白衣1 小时前
深入理解 Transformer:Transformer 究竟是什么?
java·linux·开发语言·c++·人工智能·深度学习·transformer
Tisfy4 小时前
LeetCode 1927.求和游戏:抵消+看最值
java·leetcode·游戏·题解·博弈论
秋饼10 小时前
JDK 27 企业级 AI 服务落地实战:G1 默认、紧凑对象头、后量子 TLS 与 JFR 脱敏全解析
java·ai·技术分享·后端开发
卓怡学长10 小时前
w176基于SpringBoot的医院管理系统
java·spring boot·spring·maven·intellij-idea
lemon_sjdk10 小时前
ObjectProperty
java·开发语言·算法
hh95011 小时前
Agent Plan x DeepSeek Harness:Agent 供应链安全与第三方插件审计
java·开发语言·安全·agent plan·adg成都社区·adg社区
吴声子夜歌11 小时前
Java面试——HBase原理及应用
java·面试·hbase
浪兎兎11 小时前
【Java Web】Servlet + JSP 笔记
java·前端·servlet
吴声子夜歌11 小时前
Java面试——ElasticSearch原理及应用
java·面试·es