1. 目的
本文主要解读mybatis 延迟加载实现原理
2. 延迟加载如何使用
tting 参数配置
设置参数描述有效值默认值lazyloadingenabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchtype属性来覆盖该项的开关状态。true、
falfalaggressivelazyloading当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyloadtriggermethods).true、falfal (true in ≤3.4.1)lazyloadtriggermethods指定哪个对象的方法触发一次延迟加载。用逗号分隔的方法列表。equals,clone,hashcode,tostring
配置
<configuration> <ttings> <!-- 开启延迟加载 --> <tting name="lazyloadingenabled" value="true" /> <tting name="aggressivelazyloading" value="fal" /> <tting name="lazyloadtriggermethods" value="equals,clone,hashcode,tostring" /> </ttings></configuration>
mapper 配置
<mapper namespace="org.apache.ibatis.submitted.lazy_properties.mapper"> <resultmap type="org.apache.ibatis.submitted.lazy_properties.ur" id="ur"> <id property="id" column="id" /> <result property="name" column="name" /> </resultmap> <!-- 结果对象 --> <resultmap type="org.apache.ibatis.submitted.lazy_properties.ur" id="urwithlazyproperties" extends="ur"> <!-- 延迟加载对象lazy1 --> <association property="lazy1" column="id" lect="getlazy1" fetchtype="lazy" /> <!-- 延迟加载对象lazy2 --> <association property="lazy2" column="id" lect="getlazy2" fetchtype="lazy" /> <!-- 延迟加载集合lazy3 --> <collection property="lazy3" column="id" lect="getlazy3" fetchtype="lazy" /> </resultmap> <!-- 执行的查询 --> <lect id="getur" resultmap="urwithlazyproperties"> lect * from urs where id = #{id} </lect></mapper>
ur 实体对象
public class ur implements cloneable { private integer id; private string name; private ur lazy1; private ur lazy2; private list<ur> lazy3; public int ttercounter; 省略... }
执行解析:
调用getur查询数据,从查询结果集解析数据到ur对象,当数据解析到lazy1,lazy2,lazy3判断需要执行关联查询lazyloadingenabled=true,将创建lazy1,lazy2,lazy3对应的proxy延迟执行对象lazyloader,并保存当逻辑触发lazyloadtriggermethods 对应的方法(equals,clone,hashcode,tostring)则执行延迟加载如果aggressivelazyloading=true,只要触发到对象任何的方法,就会立陈超尉即加载所有属性的加载3. 延迟加载原理实现
延迟加载主要是通过动态代理的形式实现,通过代理拦截到指定方法,执行数据加载。
mybatis延迟加载主要使用:javassist,cglib实现,类图展示:
4. 延迟加载源码解析
tting 配置加载:
public class configuration {/** aggressivelazyloading: * 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyloadtriggermethods). * 默认为个人主要事迹300字true * */ protected boolean aggressivelazyloading; /** * 延迟加载触发方法 */ protected t<string> lazyloadtriggermethods = new hasht<string>(arrays.aslist(new string[] { "equals", "clone", "hashcode", "tostring" })); /** 是否开启延迟加载 */ protected boolean lazyloadingenabled = fal; /** * 默认使用javassist代理工厂 * @param proxyfactory */ publi网名繁体c void tproxyfactory(proxyfactory proxyfactory) { if (proxyfactory == null) { proxyfactory = new javassistproxyfactory(); } this.proxyfactory = proxyfactory; } //省略...}
延迟加载代理对象创建
defaultresultthandler
//#mark 创建结果对象 private object createresultobject(resulttwrapper rsw, resultmap resultmap, resultloadermap lazyloader, string columnprefix) throws sqlexception { this.uconstructormappings = fal; // ret previous mapping result final list<class<?>> constructorargtypes = new arraylist<class<?>>(); final list<object> constructorargs = new arraylist<object>(); //#mark 创建返回的结果映射的真实对象 object resultobject = createresultobject(rsw, resultmap, constructorargtypes, constructorargs, columnprefix); if (resultobject != null && !hastypehandlerforresultobject(rsw, resultmap.gettype())) { final list<resultmapping> propertymappings = resultmap.getpropertyresultmappings(); for (resultmapping propertymapping : propertymappings) { // issue gcode #109 && issue #149 判断属性有没配置嵌套查询,如果有就创建代理对象 if (property新疆大学怎么样mapping.getnestedqueryid() != null && propertymapping.islazy()) { //#mark 创建延迟加载代理对象 resultobject = configuration.getproxyfactory().createproxy(resultobject, lazyloader, configuration, objectfactory, constructorargtypes, constructorargs); break; } } } this.uconstructormappings = resultobject != null && !constructorargtypes.impty(); // t current mapping result return resultobject; }
代理功能实现
由于javasisst和cglib的代理实现基本相同,这里主要介绍javasisst
proxyfactory接口定义
public interface proxyfactory {
void tproperties(properties properties);
/**
* 创建代理
* @param target 目标结果对象
* @param lazyloader 延迟加载对象
* @param configuration 配置
* @param objectfactory 对象工厂
* @param constructorargtypes 构造参数类型
* @param constructorargs 构造参数值
* @return
*/
object createproxy(object target, resultloadermap lazyloader, configuration configuration, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs);
}
javasisstproxyfactory实现
public class javassistproxyfactory implements org.apache.ibatis.executor.loader.proxyfactory { /** * 接口实现 * @param target 目标结果对象 * @param lazyloader 延迟加载对象 * @param configuration 配置 * @param objectfactory 对象工厂 * @param constructorargtypes 构造参数类型 * @param constructorargs 构造参数值 * @return */ @override public object createproxy(object target, resultloadermap lazyloader, configuration configuration, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { return enhancedresultobjectproxyimpl.createproxy(target, lazyloader, configuration, objectfactory, constructorargtypes, constructorargs); } //省略... /** * 代理对象实现,核心逻辑执行 */ private static class enhancedresultobjectproxyimpl implements m中泰散打对抗赛ethodhandler { /** * 创建代理对象 * @param type * @param callback * @param constructorargtypes * @param constructorargs * @return */ static object crateproxy(class<?> type, methodhandler callback, list<class<?>> constructorargtypes, list<object> constructorargs) { proxyfactory enhancer = new proxyfactory(); enhancer.tsuperclass(type); try { //通过获取对象方法,判断是否存在该方法 type.getdeclaredmethod(write_replace_method); // objectoutputstream will call writereplace of objects returned by writereplace if (log.isdebugenabled()) { log.debug(write_replace_method + " method was found on bean " + type + ", make sure it returns this"); } } catch (nosuchmethodexception e) { //没找到该方法,实现接口 enhancer.tinterfaces(new class[]{writereplaceinterface.class}); } catch (curityexception e) { // nothing to do here } object enhanced; class<?>[] typesarray = constructorargtypes.toarray(new class[constructorargtypes.size()]); object[] valuesarray = constructorargs.toarray(new object[constructorargs.size()]); try { //创建新的代理对象 enhanced = enhancer.create(typesarray, valuesarray); } catch (exception e) { throw new executorexception("error creating lazy proxy. cau: " + e, e); } //设置代理执行器 ((proxy) enhanced).thandler(callback); return enhanced; } /** * 代理对象执行 * @param enhanced 原对象 * @param method 原对象方法 * @param methodproxy 代理方法 * @param args 方法参数 * @return * @throws throwable */ @override public object invoke(object enhanced, method method, method methodproxy, object[] args) throws throwable { final string methodname = method.getname(); try { synchronized (lazyloader) { if (write_replace_method.equals(methodname)) { //忽略暂未找到具体作用 object original; if (constructorargtypes.impty()) { original = objectfactory.create(type); } el { original = objectfactory.create(type, constructorargtypes, constructorargs); } propertycopier.copybeanproperties(type, enhanced, original); if (lazyloader.size() > 0) { return new javassistrialstateholder(original, lazyloader.getproperties(), objectfactory, constructorargtypes, constructorargs); } el { return original; } } el { //延迟加载数量大于0 if (lazyloader.size() > 0 && !finalize_method.equals(methodname)) { //aggressive 一次加载性所有需要要延迟加载属性或者包含触发延迟加载方法 if (aggressive || lazyloadtriggermethods.contains(methodname)) { log.debug("==> laze lod trigger method:" + methodname + ",proxy method:" + methodproxy.getname() + " class:" + enhanced.getclass()); //一次全部加载 lazyloader.loadall(); } el if (propertynamer.istter(methodname)) { //判断是否为t方法,t方法不需要延迟加载 final string property = propertynamer.methodtoproperty(methodname); lazyloader.remove(property); } el if (propertynamer.isgetter(methodname)) { final string property = propertynamer.methodtoproperty(methodname); if (lazyloader.hasloader(property)) { //延迟加载单个属性 lazyloader.load(property); log.debug("load one :" + methodname); } } } } } return methodproxy.invoke(enhanced, args); } catch (throwable t) { throw exceptionutil.unwrapthrowable(t); } } }
5. 注意事项
idea调试问题 当配置aggressivelazyloading=true,在使用idea进行调试的时候,如果断点打到代理执行逻辑当中,你会发现延迟加载的代码永远都不能进入,总是会被提前执行。 主要产生的原因在aggressivelazyloading,因为在调试的时候,idea的debuger窗体中已经触发了延迟加载对象的方法。如图:调试还未进入lazyloader.loadall(); 实际日志已经显示延迟加载已经完成,代码与日志通过颜色区分。
本文发布于:2023-04-05 06:28:46,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/bd38a9c7b156c986ff715013efaec3ef.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:mybatis延迟加载原理(mybatis工作原理及流程).doc
本文 PDF 下载地址:mybatis延迟加载原理(mybatis工作原理及流程).pdf
留言与评论(共有 0 条评论) |