标签:rap 直接 final 执行器 添加 invoke factory from protect
本文,我们来分享 SQL 执行的第五部分,延迟加载的功能的实现,涉及 executor/loader
包。整体类图如下:
在 《精尽 MyBatis 源码分析 —— SQL 执行(四)之 ResultSetHandler》 方法中,我们已经看到延迟加载相关的代码,下面让我们一处一处来看看。
另外,如果胖友并未使用过 MyBatis 的延迟加载的功能,可以先看看 《【MyBatis框架】高级映射-延迟加载》 文章。
在 DefaultResultSetHandler 的 #getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix)
方法中,我们可以看到 ResultLoader 的身影。代码如下:
// DefaultResultSetHandler.java
|
<x>
处,因为是结果对象的构造方法中使用的值,无法使用延迟加载的功能,所以使用 ResultLoader 直接加载。org.apache.ibatis.executor.loader.ResultLoader
,结果加载器。
// ResultLoader.java
|
#loadResult()
方法,加载结果。代码如下:
// ResultLoader.java
|
<1>
处,调用 #selectList()
方法,查询结果。详细解析,见 「2.3 selectList」 。<2>
处,调用 ResultExtractor#extractObjectFromList(List<Object> list, Class<?> targetType)
方法,提取结果。详细解析,见 「3. ResultExtractor」 。<3>
处,返回结果。#selectList()
方法,查询结果。代码如下:
// ResultLoader.java
|
<1>
处,如果当前线程不是创建线程,则调用 #newExecutor()
方法,创建 Executor 对象,因为 Executor 是非线程安全的。代码如下:
// ResultLoader.java
|
<2>
处,调用 Executor#query(...)
方法,执行查询。
<3>
处,如果是新创建的 Executor 对象,则调用 Executor#close()
方法,关闭 Executor 对象。#wasNull()
方法,是否结果为空。代码如下:
// ResultLoader.java
|
org.apache.ibatis.executor.ResultExtractor
,结果提取器。代码如下:
// ResultExtractor.java
|
在 DefaultResultSetHandler 的 #getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
方法中,我们可以看到 ResultLoaderMap 的身影。代码如下:
// DefaultResultSetHandler.java
|
<x>
处,因为是结果对象的 setting 方法中使用的值,可以使用延迟加载的功能,所以使用 ResultLoaderMap 记录。最终会创建结果对象的代理对象,而 ResultLoaderMap 对象会传入其中,作为一个参数。从而能够,在加载该属性时,能够调用 ResultLoader#loadResult()
方法,加载结果。另外,在 <y>
处,检查缓存中已存在,则会调用 Executor#deferLoad(...)
方法,尝试加载结果。代码如下:
老艿艿:此处是插入,?? 找不到适合放这块内容的地方了,哈哈哈。
// 该方法在 BaseExecutor 抽象类中实现
|
org.apache.ibatis.executor.loader.ResultLoaderMap
, ResultLoader 的映射。该映射,最终创建代理对象时,会作为参数传入代理。
// ResultLoaderMap.java
|
#addLoader(String property, MetaObject metaResultObject, ResultLoader resultLoader)
方法,添加到 loaderMap
中。代码如下:
// ResultLoaderMap.java
|
其中,LoadPair 是 ResultLoaderMap 的内部静态类。代码如下:
// ResultLoaderMap.java
|
#load(String property)
方法,执行指定属性的加载。代码如下:
// ResultLoaderMap.java
|
LoadPair#load()
方法,执行加载。代码如下:
// ResultLoaderMap.java
|
<1>
和 <2>
处,胖友可以暂时无视,主要用于延迟加载在序列化和反序列化的时候,一般很少碰到。当然,感兴趣的胖友,可以调试下 org.apache.ibatis.submitted.lazy_deserialize.LazyDeserializeTest
单元测试类。<3>
处,调用 ResultLoader#loadResult()
方法,执行查询结果。<3>
处,调用 MetaObject#setValue(String name, Object value)
方法,设置属性。#loadAll()
方法,执行所有属性的加载。代码如下:
// ResultLoaderMap.java
|
ResultLoaderMap 还有其它方法,比较简单,胖友可以自己看看。
在 DefaultResultSetHandler 的 #createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix)
方法中,我们可以看到 ProxyFactory 的身影。代码如下:
// DefaultResultSetHandler.java
|
<x>
处,调用 ProxyFactory#createProxy(...)
方法,创建结果对象的代理对象。org.apache.ibatis.executor.loader.ProxyFactory
,代理工厂接口,用于创建需要延迟加载属性的结果对象。代码如下:
// ProxyFactory.java
|
ProxyFactory 有 JavassistProxyFactory 和 CglibProxyFactory 两个实现类,默认使用前者。原因见如下代码:
// Configuration.java
|
org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory
,实现 ProxyFactory 接口,基于 Javassist 的 ProxyFactory 实现类。
// JavassistProxyFactory.java
|
#createDeserializationProxy(Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
方法,创建支持反序列化的代理对象。代码如下:
// JavassistProxyFactory.java
|
#createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
方法,创建代理对象。代码如下:
// JavassistProxyFactory.java
|
#crateProxy(Class<?> type, MethodHandler callback, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
静态方法,创建代理对象。代码如下:
// JavassistProxyFactory.java
|
<x>
处,设置代理对象的执行器。该执行器,就是 EnhancedResultObjectProxyImpl 对象。详细解析,见 「5.1.5 EnhancedResultObjectProxyImpl」 。EnhancedResultObjectProxyImpl ,是 JavassistProxyFactory 的内部静态类,实现 javassist.util.proxy.MethodHandler
接口,方法处理器实现类。
// JavassistProxyFactory.java
|
涉及的 aggressive
和 lazyLoadTriggerMethods
属性,在 Configuration 定义如下:
// Configuration.java
|
#createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
方法,创建代理对象,并设置方法处理器为 EnhancedResultObjectProxyImpl 对象。代码如下:
因为方法名 createProxy 一直在重复,所以这里艿艿说下调用链:
「5.1.3 createProxy 普通方法」 => 「5.1.4.2 createProxy」 => 「5.1.4 createProxy 静态方法」
// JavassistProxyFactory.java
|
#invoke(Object enhanced, Method method, Method methodProxy, Object[] args)
方法,执行方法。代码如下:
// JavassistProxyFactory.java
|
<1.1>
处,如果满足条件,则调用 ResultLoaderMap#loadAll()
方法,加载所有延迟加载的属性。<1.2>
处,如果调用了 setting 方法,则调用 ResultLoaderMap#remove(String property)
方法,不在使用延迟加载。因为,具体的值都设置了,无需在延迟加载了。<1.3>
处,如果调用了 getting 方法,则调用 ResultLoaderMap#load(String property)
方法,执行指定属性的延迟加载。此处,就会去数据库中查询,并设置到对应的属性。<2>
处,继续执行原方法。org.apache.ibatis.executor.loader.cglib.CglibProxyFactory
,实现 ProxyFactory 接口,基于 Cglib 的 ProxyFactory 实现类。
标签:rap 直接 final 执行器 添加 invoke factory from protect
原文地址:https://www.cnblogs.com/siye1989/p/11624263.html