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个实现类,cglibproxyfactory
和javassistproxyfactor
类。这两个实现类整体结构高度一致,内部类、方法设置都一样,只是实现原理不同。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 条评论) |