【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 接口的代理对象,而不需要为每个接口单独处理创建逻辑。

相关推荐
Coder码匠22 分钟前
Dockerfile 优化实践:从 400MB 到 80MB
java·spring boot
李慕婉学姐8 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆9 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin10 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model200510 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉10 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国10 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_9418824810 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈11 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_9911 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc