一文带你了解Mybatis延迟加载原理源码解析

这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

Mybatis延迟加载原理源码解析

Mybatis基本结构图

image.png

由上图可以知道MyBatis延迟加载主要使⽤:JavassistProxyFactory,CgliProxyFactoryb实现类。这两种实现类就对应着Mybatis的延迟加载的Javassist和Cgli实现,ProxyFactory默认使用JavassistProxyFactory进行实现

Spring配置加载

只要在xml中配置全局二级缓存的值,所有的值都能在Configuration中找到,并且可以找到对应的源码

image.png

image.png

延迟加载代理对象创建

Mybatis的查询结果是由ResultSetHandler接⼝的handleResultSets()⽅法处理的。ResultSetHandler接⼝只有⼀个实现DefaultResultSetHandler,DefaultResultSetHandler类中的createResultObeject方法其实就是延迟加载相关的一个核心方法,接下来看下createResultObeject方法

image.png

由图上代码可以知道,该方法一开始是创建记录初始方法的数组等,然后通过createResuleObject重载方法创建映射后的结果对象,然后就代表创建的是user对象,判断结果对象是否空,如果不为空,则开启延迟加载并且创建结果对象的代理对象,通过resultMap读取到xml里面的对象属性,进入for循环中,判断当前属性是否有配置延迟加载的对象,如果有,则通过configuration.getProxyFactory().createProxy()方法进行代理对象的创建, 因此延迟加载默认采⽤javassistProxy进⾏代理对象的创建

image.png

JavasisstProxyFactory代码实现

image.png

image.png

有上图源码可知:创建EnhancedResultObjectProxyImpl对象是由类加载器、被调用实现的接口以及Enhanced底层实现,EnhancedResultObjectProxyImpl就相当于JDK动态代理中Enhanced的具体实现类,如果当代理对象调用方法是,就会找到类中invoke方法,具体代码实现如下图所示

image.png

image.png

锁后面的if部分方法主要是与序列化实现相关,在此不过多讨论,直接看到else后面的代码,首先判断aggressive是true还是false,如果为true,则表示加载所有的延迟加载属性,lazyLoadTriggerMethods.contains(methodName)是否包含mehtodName的方法,如果都不通过,则进行下一步的判断,是否调用啦setting()方法的,表示不使用延迟加载,如果没有调用setting方法,则进行下一步的判断,是否调用啦getting()方法,表示要执行延迟加载,如果上述三种都没有通过,则继续执行原方法。

延迟加载调试注意事项

IDEA调试问题当配置aggressiveLazyLoading=true,在使⽤IDEA进⾏调试的时候,如果断点打到代理执⾏逻辑当中,你会发现延迟加载的代码永远都不能进⼊,总是会被提前执⾏。主要产⽣的原因在aggressiveLazyLoading,因为在调试的时候,IDEA的Debuger窗体中已经触发了延迟加载对象的⽅法。

おすすめ

転載: juejin.im/post/7035059992986124318