首页 > 作文

mybatis源码解读之executor包懒加载功能

更新时间:2023-04-05 01:12:16 阅读: 评论:0

proxyfactory是创建代理类的工厂接口,其中的tproperties方法用来对工厂进行属性设置,但是mybatis内置的两个实现类都没有实现该接口,所以不支持属性设置。createproxy方法用来创建一个代理对象

public interface proxyfactory { // 设置工厂属性 default void tproperties(properties properties) { } // 创建代理对象 object createproxy(object target, resultloadermap lazyloader, configuration configuration, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs);}

proxyfactory接口有2个实现类,cglibproxyfactoryjavassistproxyfactor类。这两个实现类整体结构高度一致,内部类、方法设置都一样,只是实现原理不同。cglibproxyfactory基于cglib实现,javassistproxyfactor基于javassist实现。

接下来以cglibproxyfactory类为源码进行分析:

cglibproxyfactory类中提供了两个创建代理对象的方法。其中createproxy方法重写了一个普通的代理对象,createderializationproxy方法用来创建一个反序列化的代理对象。

public class cglibproxyfactory implements proxyfactory { private static final string finalize_method = "finalize"; private static final string write_replace_method = "writereplace"; public cglibproxyfactory() {  try {   resources.classforname("net.sf.cglib.proxy.enhancer");  } catch (throwable e) {   throw new illegalstateexception("cannot enable lazy loading becau cglib is not available. add cglib to your classpath.", e);  } } // 创建一个代理 @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); } // 创建一个反序列化的代理 public object createderializationproxy(object target, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) {  return enhancedderializationproxyimpl.createproxy(target, unloadedproperties, objectfactory, constructorargtypes, constructorargs); } private static class enhancedresultobjectproxyimpl implements methodinterceptor {  // 被代理类  private final class<?> type;  // 要懒加载的属性map  private final resultloadermap lazyloader;  // 是否是激进懒加载  private final boolean aggressive;  // 能够触发懒加载的方法名“equals”, “clone”, “hashcode”, “tostring”。这四个方法名在configuration中被初始化。  private final t<string> lazyloadtriggermethods;  // 对象工厂  private final objectfactory objectfactory;  // 被代理类构造函数的参数类型列表  private final list<class<?>> constructorargtypes;  // 被代理类构造函数的参数列表  private final list<object> construct谢铭佑orargs;  private enhancedresultobjectproxyimpl(class<?> type, resultloadermap lazyloader, configuration configuration, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) {   this.type = type;   this.lazyloader = lazyloader;   this.aggressive = configuration.isaggressivelazyloading();   this.lazyloadtriggermethods = configuration.getlazyloadtriggermethods();   this.objectfactory = objectfactory;   this.constructorargtypes = constructorargtypes;   this.constructorargs = constructorargs;  }  public static object createproxy(object target, resultloadermap lazyloader, configuration configuration, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) {   final class<?> type = target.getclass();   enhancedresultobjectproxyimpl callback = new enhancedresultobjectproxyimpl(type, lazyloader, configuration, objectfactory, constructorargtypes, constructorargs);   object enhanced = crateproxy(type, callback, constructorargtypes, constructorargs);   propertycopier.copybeanproperties(type, target, enhanced);   return enhanced;  }  /**  * 代理类的拦截方法  * @param enhanced 代理对象本身  * @param method 被调用的方法  * @param args 每调用的方法的参数  * @param methodproxy 用来调用父类的代理  * @return 方法返回值  * @throws throwable  */  @override  public object intercept(object enhanced, method method, object[] args, methodproxy methodproxy) throws throwable {   // 取出被代理类中此次被调上海建桥用的方法的名称   final string methodname = method.getname();   try {    synchronized (lazyloader) { // 防止属性的并发加载     if (write_replace_method.equals(methodname)) { // 被调用的是writereplace方法      // 创建一个原始对象      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) { // 存在懒加载属性       // 则此时返回的信息要更多,不仅仅是原对象,还有相关的懒加载的设置等信息。因此使用cglibrialstateholder进行一次封装       return new cglibrialstateholder(original, lazyloader.getproperties(), objectfactory, constructorargtypes, constructorargs);      } el {       // 没有未懒加载的属性了,那直接返回原对象进行序列化       return original;      }     } el {      if (lazyloader.size() > 0 && !finalize_method.equals(methodname)) { // 存在懒加载属性且被调用的不是finalize方法       if (aggressive || lazyloadtriggermethods.contains(methodname)) { // 设置了激进懒加载或者被调用的方法是能够触发全局懒加载的方法        // 完成所有属性的懒加载        lazyloader.loadall();       } el if (propertynamer.istter(methodname)) { // 调用了属性写方法        // 则先清除该属性的懒加载设置。该属性不需要被懒加载了        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);        }       }      }     }    }    // 触发被代理类的相应方法。能够进行到这里的是除去writereplace方法外的方法,例如读写方法、tostring方法等    return methodproxy.invokesuper(enhanced, args);   } catch (throwable t) {    throw exceptionutil.unwrapthrowable(t);   }  } } }

代理类最核地理环境的整体性心的方法是intercept方法,当被代理对象的其他方法被调用时,intercept方法的处理方式是:

如果设置了激进懒加载或者被调用的是触发全局加载的方法,则直接加载所有未加载的属性。

如果被调用的是属性写方法,则将该方法从懒加载列表中删除,因为此时数据库中的数据已经不是最新的,没有必要再去加载,然后进行属性的写入操作。

如果被调用的是读方法,则该属性尚未被懒加载的情况下,则加载该属性,如果该属性已经被懒加载过,则直接读取该属性。

resultloadermap类:

被代理对象可能会有多个属性可以被懒加载,这些尚未完成加载的属性是在resultloadermap类的实例中存储的。resultloadermap类主要就是一个map类,该类key为属性名的大写,value为loadpair对象。loadpair类是resultloadermap类的内部类,它能实现对应属性的懒加载功能。

public static class loadpair implements rializable {  private static final long rialversionuid = 20130412;  // 用来根据反射得到数据库连接的方法名  private static final string factory_method = "getconfiguration";   // 判断是否经过了序列化的标志位,因为该属性被设置了transient,经过一次序列化和反序列化后会变为null  private final transient object rializationcheck = new object();   // 输出结果对象的封装  private transient metaobject metaresultobject;   // 用以加载未加载属性的加载器  private transient resultloader resultloader;  // 日志记录器  private transient log log;   // 用来获取数据库连接的工厂  private class<?> configurationfactory;   // 未加载的属性的属性名  private string property;   // 能够加载未加载属性的sql的编号  private string mappedstatement;  // 能够加载未加载属性的sql的参数  private rializable mappedparameter;  private loadpair(final string property, metaobject metaresultobject, resultloader resultloader) {   this.property = property;   this.metaresultobject = metaresultobject;   this.resultloader = resultloader;   if (metaresultobject != null && metaresultobject.getoriginalobject() instanceof rializable) {    final object mappedstatementparameter = resultloader.parameterobject;    if (mappedstatementparameter instanceof rializable) {     this.mappedstatement = resultloader.mappedstatement.getid();     this.mappedparameter = (rializable) mappedstatementparameter;     this.configurationfactory = resultloader.configuration.getconfigurationfactory();    } el {     log log = this.getlogger();     if (log.isdebugenabled()) {      log.debug("property [" + this.property + "] of ["          + metaresultobject.getoriginalobject().getclass() + "] cannot be loaded "          + "after derialization. make sure it's loaded before rializing "          + "forenamed object.");     }    }   }  }  public void load() throws sqlexception {   if (this.metaresultobject == null) {    throw new illegalargumentexception("metaresultobject is null");   }   if (this.resultloader == null) {    throw new illegalargumentexception("resultloader is null");   }   this.load(null);  }  /**  * 进行加载操作  * @param urobject 需要被懒加载的对象(只有当this.metaresultobject == null || this.resultloader == null才生效,否则会采用属性metaresultobject对应的对象)  * @throws sqlexception  */  public void load(final object urobject) throws sqlexception {   if (this.metaresultobject == null || this.resultloader == null) { // 输出结果对象的封装不存在或者输出结果加载器不存在    // 判断用以加载属性的对应的sql语句存在    if (this.mappedparameter == null) {     throw new executorexception("property [" + this.property + "] cannot be loaded becau "         + "required parameter of mapped statement ["         + this.mappedstatement + "] is not rializable.");    }    final configuration config = this.getconfiguration();    // 取出用来加载结果的sql语句    final mappedstatement ms = config.getmappedstatement(this.mappedstatement);    if (ms == null) {     throw new executorexception("cannot lazy load property [" + this.property         + "] of derialized object [" + urobject.getclass()         + "] becau configuration does not contain statement ["         + this.mappedstatement + "]");    }    // 创建结果对象的包装    this.metaresultobject = config.newmetaobject(urobject);    // 创建结果加载器    this.resultloader = new resultloader(config, new clodexecutor(), ms, this.mappedparameter,        metaresultobject.getttertype(this.property), null, null);   }   // 只要经历过持久化,则可能在别的线程中了。为这次惰性加载创建的新线程resultloader   if (this.rializationcheck == null) {    // 取出原来的resultloader中的必要信息,然后创建一个新的    // 这是因为load函数可能在不同的时间多次执行(第一次加载属性a,又过了好久加载属性b)。    // 而该对象的各种属性是跟随对象的,加载属性b时还保留着加载属性a时的状态,即resultloader是加载属性a时设置的    // 则此时resultloader中的executor在resultloader中被替换成了一个能运行的executor,而不是clodexecutor    // 能运行的executor的状态可能不是clo,这将导致它被复用,从而引发多线程问题    // 是不是被两次执行的一个关键点就是有没有经过序列化,因为执行完后会被序列化并持久化    final resultloader old = this.resultloader;    this.resultloader = new resultloader(old.configuration, new clodexecutor(), old.mappedstatement,        old.parameterobject, old.targettype, old.cachekey, old.boundsql);   }   this.metaresultobject.tvalue(property, this.resultloader.loadresult());  }  private configuration getconfiguration() {   if (this.configurationfactory == null) {    throw new executorexception("cannot get configuration as configuration factory was not t.");   }   object configurationobject;   try {    final method factorymethod = this.configurationfactory.getdeclaredmethod(factory_method);    if (!modifier.isstatic(factorymethod.getmodifiers())) {     throw new executorexception("cannot get configuration as factory method ["         + this.configurationfactory + "]#["         + factory_method + "] is not static.");    }    if (!factorymethod.isaccessible()) {     configurationobject = accesscontroller.doprivileged((privilegedexceptionaction<object>) () -> {      try {       factorymethod.taccessible(true);       return factorymethod.invoke(null);      } finally {       factorymethod.taccessible(fal);      }     });    } el {     configurationo西江月夜行黄沙道中的意思bject = factorymethod.invoke(null);什么老虎不吃人脑筋急转弯    }   } catch (final executorexception ex) {    throw ex;   } catch (final nosuchmethodexception ex) {    throw new executorexception("cannot get configuration as factory class ["        + this.configurationfactory + "] is missing factory method of name ["        + factory_method + "].", ex);   } catch (final privilegedactionexception ex) {    throw new executorexception("cannot get configuration as factory method ["        + this.configurationfactory + "]#["        + factory_method + "] threw an exception.", ex.getcau());   } catch (final exception ex) {    throw new executorexception("cannot get configuration as factory method ["        + this.configurationfactory + "]#["        + factory_method + "] threw an exception.", ex);   }   if (!(configurationobject instanceof configuration)) {    throw new executorexception("cannot get configuration as factory method ["        + this.configurationfactory + "]#["        + factory_method + "] didn't return [" + configuration.class + "] but ["        + (configurationobject == null ? "null" : configurationobject.getclass()) + "].");   }   return configuration.class.cast(configurationobject);  }  private log getlogger() {   if (this.log == null) {    this.log = logfactory.getlog(this.getclass());   }   return this.log;  } }

到此这篇关于mybatis源码解读之executor包懒加载功能 的文章就介绍到这了,更多相关executor包懒加载功能 内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

本文发布于:2023-04-05 01:12:14,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/e795512fe4c5de7b339cc3089937eb39.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:mybatis源码解读之executor包懒加载功能.doc

本文 PDF 下载地址:mybatis源码解读之executor包懒加载功能.pdf

标签:加载   属性   方法   对象
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图