Mybaits 源码解析 (八)----- 全网最详细,没有之一:结果集 ResultSet 自动映射成实体类对象(上篇)
上一篇文章我们已经将sql发送到了数据库,并返回了resultset,接下来就是将结果集 resultset 自动映射成实体类对象。这样使用者就无需再手动操作结果集,并将数据填充到实体类对象中。这可大大降低开发的工作量,提高工作效率。
映射结果入口
我们来看看上次看源码的位置
public <e> list<e> query(statement statement, resulthandler resulthandler) throws sqlexception { preparedstatement ps = (preparedstatement)statement; //执行数据库sql ps.execute(); //进行resultset自动映射 return this.resultsethandler.handleresultsets(ps); }
结果集的处理入口方法是 handleresultsets
public list<object> handleresultsets(statement stmt) throws sqlexception { final list<object> multipleresults = new arraylist<object>(); int resultsetcount = 0; //获取第一个resultset,通常只会有一个 resultsetwrapper rsw = getfirstresultset(stmt); //从配置中读取对应的resultmap,通常也只会有一个,设置多个是通过逗号来分隔,我们平时有这样设置吗? list<resultmap> resultmaps = mappedstatement.getresultmaps(); int resultmapcount = resultmaps.size(); validateresultmapscount(rsw, resultmapcount); while (rsw != null && resultmapcount > resultsetcount) { resultmap resultmap = resultmaps.get(resultsetcount); // 处理结果集 handleresultset(rsw, resultmap, multipleresults, null); rsw = getnextresultset(stmt); cleanupafterhandlingresultset(); resultsetcount++; } // 以下逻辑均与多结果集有关,就不分析了,代码省略 string[] resultsets = mappedstatement.getresultsets(); if (resultsets != null) {...} return collapsesingleresultlist(multipleresults); }
在实际运行过程中,通常情况下一个sql语句只返回一个结果集,对多个结果集的情况不做分析 。实际很少用到。继续看handleresultset方法
private void handleresultset(resultsetwrapper rsw, resultmap resultmap, list<object> multipleresults, resultmapping parentmapping) throws sqlexception { try { if (parentmapping != null) { handlerowvalues(rsw, resultmap, null, rowbounds.default, parentmapping); } else { if (resulthandler == null) { // 创建默认的结果处理器 defaultresulthandler defaultresulthandler = new defaultresulthandler(objectfactory); // 处理结果集的行数据 handlerowvalues(rsw, resultmap, defaultresulthandler, rowbounds, null); // 将结果加入multipleresults中 multipleresults.add(defaultresulthandler.getresultlist()); } else { handlerowvalues(rsw, resultmap, resulthandler, rowbounds, null); } } } finally { closeresultset(rsw.getresultset()); } }
通过handlerowvalues 映射resultset结果,最后映射的结果会在defaultresulthandler的resultlist集合中,最后将结果加入到multipleresults中就可以返回了,我们继续跟进handlerowvalues这个核心方法
public void handlerowvalues(resultsetwrapper rsw, resultmap resultmap, resulthandler<?> resulthandler, rowbounds rowbounds, resultmapping parentmapping) throws sqlexception { if (resultmap.hasnestedresultmaps()) { ensurenorowbounds(); checkresulthandler(); // 处理嵌套映射,关于嵌套映射我们下一篇文章单独分析 handlerowvaluesfornestedresultmap(rsw, resultmap, resulthandler, rowbounds, parentmapping); } else { // 处理简单映射,本文先只分析简单映射 handlerowvaluesforsimpleresultmap(rsw, resultmap, resulthandler, rowbounds, parentmapping); } }
我们可以通过resultmap.hasnestedresultmaps()知道查询语句是否是嵌套查询,如果resultmap中包含<association> 和 <collection>且其select属性不为空,则为嵌套查询,大家可以看看我第三篇文章关于解析 resultmap 节点。本文先分析简单的映射
private void handlerowvaluesforsimpleresultmap(resultsetwrapper rsw, resultmap resultmap, resulthandler<?> resulthandler, rowbounds rowbounds, resultmapping parentmapping) throws sqlexception { defaultresultcontext<object> resultcontext = new defaultresultcontext<object>(); // 根据 rowbounds 定位到指定行记录 skiprows(rsw.getresultset(), rowbounds); // resultset是一个集合,很有可能我们查询的就是一个list,这就就每条数据遍历处理 while (shouldprocessmorerows(resultcontext, rowbounds) && rsw.getresultset().next()) { resultmap discriminatedresultmap = resolvediscriminatedresultmap(rsw.getresultset(), resultmap, null); // 从 resultset 中获取结果 object rowvalue = getrowvalue(rsw, discriminatedresultmap); // 存储结果到resulthandler的resultlist,最后resultlist加入multipleresults中返回 storeobject(resulthandler, resultcontext, rowvalue, parentmapping, rsw.getresultset()); } }
我们查询的结果很有可能是一个集合,所以这里要遍历集合,每条结果单独进行映射,最后映射的结果加入到resulthandler的resultlist
mybatis 默认提供了 rowbounds 用于分页,从上面的代码中可以看出,这并非是一个高效的分页方式,是查出所有的数据,进行内存分页。除了使用 rowbounds,还可以使用一些第三方分页插件进行分页。我们后面文章来讲,我们来看关键代码getrowvalue,处理一行数据
private object getrowvalue(resultsetwrapper rsw, resultmap resultmap) throws sqlexception { // 这个map是用来存储延迟加载的bountsql的,我们下面来看 final resultloadermap lazyloader = new resultloadermap(); // 创建实体类对象,比如 employ 对象 object rowvalue = createresultobject(rsw, resultmap, lazyloader, null); if (rowvalue != null && !hastypehandlerforresultobject(rsw, resultmap.gettype())) { final metaobject metaobject = configuration.newmetaobject(rowvalue); boolean foundvalues = this.useconstructormappings; if (shouldapplyautomaticmappings(resultmap, false)) { //自动映射,结果集中有的column,但resultmap中并没有配置 foundvalues = applyautomaticmappings(rsw, resultmap, metaobject, null) || foundvalues; } // 根据 <resultmap> 节点中配置的映射关系进行映射 foundvalues = applypropertymappings(rsw, resultmap, metaobject, lazyloader, null) || foundvalues; foundvalues = lazyloader.size() > 0 || foundvalues; rowvalue = foundvalues || configuration.isreturninstanceforemptyrow() ? rowvalue : null; } return rowvalue; }
重要的逻辑已经注释出来了。分别如下:
- 创建实体类对象
-
自动映射结果集中有的column,但resultmap中并没有配置
-
根据 <resultmap> 节点中配置的映射关系进行映射
创建实体类对象
我们想将查询结果映射成实体类对象,第一步当然是要创建实体类对象了,下面我们来看一下 mybatis 创建实体类对象的过程。
private object createresultobject(resultsetwrapper rsw, resultmap resultmap, resultloadermap lazyloader, string columnprefix) throws sqlexception { this.useconstructormappings = false; final list<class<?>> constructorargtypes = new arraylist<class<?>>(); final list<object> constructorargs = new arraylist<object>(); // 调用重载方法创建实体类对象 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) { // 如果开启了延迟加载,则为 resultobject 生成代理类,如果仅仅是配置的关联查询,没有开启延迟加载,是不会创建代理类 if (propertymapping.getnestedqueryid() != null && propertymapping.islazy()) { /* * 创建代理类,默认使用 javassist 框架生成代理类。 * 由于实体类通常不会实现接口,所以不能使用 jdk 动态代理 api 为实体类生成代理。 * 并且将lazyloader传进去了 */ resultobject = configuration.getproxyfactory() .createproxy(resultobject, lazyloader, configuration, objectfactory, constructorargtypes, constructorargs); break; } } } this.useconstructormappings = resultobject != null && !constructorargtypes.isempty(); return resultobject; }
我们先来看 createresultobject 重载方法的逻辑
private object createresultobject(resultsetwrapper rsw, resultmap resultmap, list<class<?>> constructorargtypes, list<object> constructorargs, string columnprefix) throws sqlexception { final class<?> resulttype = resultmap.gettype(); final metaclass metatype = metaclass.forclass(resulttype, reflectorfactory); final list<resultmapping> constructormappings = resultmap.getconstructorresultmappings(); if (hastypehandlerforresultobject(rsw, resulttype)) { return createprimitiveresultobject(rsw, resultmap, columnprefix); } else if (!constructormappings.isempty()) { return createparameterizedresultobject(rsw, resulttype, constructormappings, constructorargtypes, constructorargs, columnprefix); } else if (resulttype.isinterface() || metatype.hasdefaultconstructor()) { // 通过 objectfactory 调用目标类的默认构造方法创建实例 return objectfactory.create(resulttype); } else if (shouldapplyautomaticmappings(resultmap, false)) { return createbyconstructorsignature(rsw, resulttype, constructorargtypes, constructorargs, columnprefix); } throw new executorexception("do not know how to create an instance of " + resulttype); }
一般情况下,mybatis 会通过 objectfactory 调用默认构造方法创建实体类对象。看看是如何创建的
public <t> t create(class<t> type, list<class<?>> constructorargtypes, list<object> constructorargs) { class<?> classtocreate = this.resolveinterface(type); return this.instantiateclass(classtocreate, constructorargtypes, constructorargs); } <t> t instantiateclass(class<t> type, list<class<?>> constructorargtypes, list<object> constructorargs) { try { constructor constructor; if (constructorargtypes != null && constructorargs != null) { constructor = type.getdeclaredconstructor((class[])constructorargtypes.toarray(new class[constructorargtypes.size()])); if (!constructor.isaccessible()) { constructor.setaccessible(true); } return constructor.newinstance(constructorargs.toarray(new object[constructorargs.size()])); } else { //通过反射获取构造器 constructor = type.getdeclaredconstructor(); if (!constructor.isaccessible()) { constructor.setaccessible(true); } //通过构造器来实例化对象 return constructor.newinstance(); } } catch (exception var9) { throw new reflectionexception("error instantiating " + type + " with invalid types (" + argtypes + ") or values (" + argvalues + "). cause: " + var9, var9); } }
很简单,就是通过反射创建对象
结果集映射
映射结果集分为两种情况:一种是自动映射(结果集有但在resultmap里没有配置的字段),在实际应用中,都会使用自动映射,减少配置的工作。自动映射在mybatis中也是默认开启的。第二种是映射resultmap中配置的,我们分这两者映射来看
自动映射
private boolean applyautomaticmappings(resultsetwrapper rsw, resultmap resultmap, metaobject metaobject, string columnprefix) throws sqlexception { // 获取 unmappedcolumnautomapping 列表 list<unmappedcolumnautomapping> automapping = createautomaticmappings(rsw, resultmap, metaobject, columnprefix); boolean foundvalues = false; if (!automapping.isempty()) { for (unmappedcolumnautomapping mapping : automapping) { // 通过 typehandler 从结果集中获取指定列的数据 final object value = mapping.typehandler.getresult(rsw.getresultset(), mapping.column); if (value != null) { foundvalues = true; } if (value != null || (configuration.iscallsettersonnulls() && !mapping.primitive)) { // 通过元信息对象设置 value 到实体类对象的指定字段上 metaobject.setvalue(mapping.property, value); } } } return foundvalues; }
首先是获取 unmappedcolumnautomapping 集合,然后遍历该集合,并通过 typehandler 从结果集中获取数据,最后再将获取到的数据设置到实体类对象中。
unmappedcolumnautomapping 用于记录未配置在 <resultmap> 节点中的映射关系。它的代码如下:
private static class unmappedcolumnautomapping { private final string column; private final string property; private final typehandler<?> typehandler; private final boolean primitive; public unmappedcolumnautomapping(string column, string property, typehandler<?> typehandler, boolean primitive) { this.column = column; this.property = property; this.typehandler = typehandler; this.primitive = primitive; } }
仅用于记录映射关系。下面看一下获取 unmappedcolumnautomapping 集合的过程,如下:
private list<unmappedcolumnautomapping> createautomaticmappings(resultsetwrapper rsw, resultmap resultmap, metaobject metaobject, string columnprefix) throws sqlexception { final string mapkey = resultmap.getid() + ":" + columnprefix; // 从缓存中获取 unmappedcolumnautomapping 列表 list<unmappedcolumnautomapping> automapping = automappingscache.get(mapkey); // 缓存未命中 if (automapping == null) { automapping = new arraylist<unmappedcolumnautomapping>(); // 从 resultsetwrapper 中获取未配置在 <resultmap> 中的列名 final list<string> unmappedcolumnnames = rsw.getunmappedcolumnnames(resultmap, columnprefix); for (string columnname : unmappedcolumnnames) { string propertyname = columnname; if (columnprefix != null && !columnprefix.isempty()) { if (columnname.touppercase(locale.english).startswith(columnprefix)) { propertyname = columnname.substring(columnprefix.length()); } else { continue; } } // 将下划线形式的列名转成驼峰式,比如 author_name -> authorname final string property = metaobject.findproperty(propertyname, configuration.ismapunderscoretocamelcase()); if (property != null && metaobject.hassetter(property)) { // 检测当前属性是否存在于 resultmap 中 if (resultmap.getmappedproperties().contains(property)) { continue; } // 获取属性对于的类型 final class<?> propertytype = metaobject.getsettertype(property); if (typehandlerregistry.hastypehandler(propertytype, rsw.getjdbctype(columnname))) { final typehandler<?> typehandler = rsw.gettypehandler(propertytype, columnname); // 封装上面获取到的信息到 unmappedcolumnautomapping 对象中 automapping.add(new unmappedcolumnautomapping(columnname, property, typehandler, propertytype.isprimitive())); } else { configuration.getautomappingunknowncolumnbehavior() .doaction(mappedstatement, columnname, property, propertytype); } } else { configuration.getautomappingunknowncolumnbehavior() .doaction(mappedstatement, columnname, (property != null) ? property : propertyname, null); } } // 写入缓存 automappingscache.put(mapkey, automapping); } return automapping; }
先来看看从 resultsetwrapper 中获取未配置在 <resultmap> 中的列名
public list<string> getunmappedcolumnnames(resultmap resultmap, string columnprefix) throws sqlexception { list<string> unmappedcolumnnames = unmappedcolumnnamesmap.get(getmapkey(resultmap, columnprefix)); if (unmappedcolumnnames == null) { // 加载已映射与未映射列名 loadmappedandunmappedcolumnnames(resultmap, columnprefix); // 获取未映射列名 unmappedcolumnnames = unmappedcolumnnamesmap.get(getmapkey(resultmap, columnprefix)); } return unmappedcolumnnames; } private void loadmappedandunmappedcolumnnames(resultmap resultmap, string columnprefix) throws sqlexception { list<string> mappedcolumnnames = new arraylist<string>(); list<string> unmappedcolumnnames = new arraylist<string>(); final string uppercolumnprefix = columnprefix == null ? null : columnprefix.touppercase(locale.english); // 获取 <resultmap> 中配置的所有列名 final set<string> mappedcolumns = prependprefixes(resultmap.getmappedcolumns(), uppercolumnprefix); /* * 遍历 columnnames,columnnames 是 resultsetwrapper 的成员变量,保存了当前结果集中的所有列名 * 这里是通过resultset中的所有列名来获取没有在resultmap中配置的列名 * 意思是后面进行自动赋值时,只赋值查出来的列名 */ for (string columnname : columnnames) { final string uppercolumnname = columnname.touppercase(locale.english); // 检测已映射列名集合中是否包含当前列名 if (mappedcolumns.contains(uppercolumnname)) { mappedcolumnnames.add(uppercolumnname); } else { // 将列名存入 unmappedcolumnnames 中 unmappedcolumnnames.add(columnname); } } // 缓存列名集合 mappedcolumnnamesmap.put(getmapkey(resultmap, columnprefix), mappedcolumnnames); unmappedcolumnnamesmap.put(getmapkey(resultmap, columnprefix), unmappedcolumnnames); }
首先是从当前数据集中获取列名集合,然后获取 <resultmap> 中配置的列名集合。之后遍历数据集中的列名集合,并判断列名是否被配置在了 <resultmap> 节点中。若配置了,则表明该列名已有映射关系,此时该列名存入 mappedcolumnnames 中。若未配置,则表明列名未与实体类的某个字段形成映射关系,此时该列名存入 unmappedcolumnnames 中。
映射result节点
接下来分析一下 mybatis 是如何将结果集中的数据填充到已配置resultmap映射的实体类字段中的。
private boolean applypropertymappings(resultsetwrapper rsw, resultmap resultmap, metaobject metaobject,resultloadermap lazyloader, string columnprefix) throws sqlexception { // 获取已映射的列名 final list<string> mappedcolumnnames = rsw.getmappedcolumnnames(resultmap, columnprefix); boolean foundvalues = false; // 获取 resultmapping集合 final list<resultmapping> propertymappings = resultmap.getpropertyresultmappings(); // 所有的resultmapping遍历进行映射 for (resultmapping propertymapping : propertymappings) { string column = prependprefix(propertymapping.getcolumn(), columnprefix); if (propertymapping.getnestedresultmapid() != null) { column = null; } if (propertymapping.iscompositeresult() || (column != null && mappedcolumnnames.contains(column.touppercase(locale.english))) || propertymapping.getresultset() != null) { // 从结果集中获取指定列的数据 object value = getpropertymappingvalue(rsw.getresultset(), metaobject, propertymapping, lazyloader, columnprefix); final string property = propertymapping.getproperty(); if (property == null) { continue; // 若获取到的值为 defered,则延迟加载该值 } else if (value == defered) { foundvalues = true; continue; } if (value != null) { foundvalues = true; } if (value != null || (configuration.iscallsettersonnulls() && !metaobject.getsettertype(property).isprimitive())) { // 将获取到的值设置到实体类对象中 metaobject.setvalue(property, value); } } } return foundvalues; } private object getpropertymappingvalue(resultset rs, metaobject metaresultobject, resultmapping propertymapping,resultloadermap lazyloader, string columnprefix) throws sqlexception { if (propertymapping.getnestedqueryid() != null) { // 获取关联查询结果 return getnestedquerymappingvalue(rs, metaresultobject, propertymapping, lazyloader, columnprefix); } else if (propertymapping.getresultset() != null) { addpendingchildrelation(rs, metaresultobject, propertymapping); return defered; } else { final typehandler<?> typehandler = propertymapping.gettypehandler(); final string column = prependprefix(propertymapping.getcolumn(), columnprefix); // 从 resultset 中获取指定列的值 return typehandler.getresult(rs, column); } }
从 resultmap 获取映射对象 resultmapping 集合。然后遍历 resultmapping 集合,再此过程中调用 getpropertymappingvalue 获取指定指定列的数据,最后将获取到的数据设置到实体类对象中。
这里和自动映射有一点不同,自动映射是从直接从resultset 中获取指定列的值,但是通过resultmap多了一种情况,那就是关联查询,也可以说是延迟查询,此关联查询如果没有配置延迟加载,那么就要获取关联查询的值,如果配置了延迟加载,则返回defered
关联查询与延迟加载
我们的查询经常会碰到一对一,一对多的情况,通常我们可以用一条 sql 进行多表查询完成任务。当然我们也可以使用关联查询,将一条 sql 拆成两条去完成查询任务。mybatis 提供了两个标签用于支持一对一和一对多的使用场景,分别是 <association> 和 <collection>。下面我来演示一下如何使用 <association> 完成一对一的关联查询。先来看看实体类的定义:
/** 作者类 */ public class author { private integer id; private string name; private integer age; private integer sex; private string email; // 省略 getter/setter } /** 文章类 */ public class article { private integer id; private string title; // 一对一关系 private author author; private string content; private date createtime; // 省略 getter/setter }
接下来看一下 mapper 接口与映射文件的定义。
public interface articledao { article findone(@param("id") int id); author findauthor(@param("id") int authorid); }
<mapper namespace="xyz.coolblog.dao.articledao"> <resultmap id="articleresult" type="article"> <result property="createtime" column="create_time"/> //column 属性值仅包含列信息,参数类型为 author_id 列对应的类型,这里为 integer //意思是将author_id做为参数传给关联的查询语句findauthor <association property="author" column="author_id" javatype="author" select="findauthor"/> </resultmap> <select id="findone" resultmap="articleresult"> select id, author_id, title, content, create_time from article where id = #{id} </select> <select id="findauthor" resulttype="author"> select id, name, age, sex, email from author where id = #{id} </select> </mapper>
开启延迟加载
<!-- 开启延迟加载 --> <setting name="lazyloadingenabled" value="true"/> <!-- 关闭积极的加载策略 --> <setting name="aggressivelazyloading" value="false"/> <!-- 延迟加载的触发方法 --> <setting name="lazyloadtriggermethods" value="equals,hashcode"/>
此时association节点使用了select指向另外一个查询语句,并且将 author_id作为参数传给关联查询的语句
此时如果不开启延迟加载,那么会生成两条sql,先执行findone,然后通过findone的返回结果做为参数,执行findauthor语句,并将结果设置到author属性
如果开启了延迟加载呢?那么只会执行findone一条sql,当调用article.getauthor()方法时,才会去执行findauthor进行查询,我们下面来看看是如何实现的
我们还是要从上面映射result节点说起
private object getpropertymappingvalue(resultset rs, metaobject metaresultobject, resultmapping propertymapping,resultloadermap lazyloader, string columnprefix) throws sqlexception { if (propertymapping.getnestedqueryid() != null) { // 获取关联查询结果 return getnestedquerymappingvalue(rs, metaresultobject, propertymapping, lazyloader, columnprefix); } else if (propertymapping.getresultset() != null) { addpendingchildrelation(rs, metaresultobject, propertymapping); return defered; } else { final typehandler<?> typehandler = propertymapping.gettypehandler(); final string column = prependprefix(propertymapping.getcolumn(), columnprefix); // 从 resultset 中获取指定列的值 return typehandler.getresult(rs, column); } }
我们看到,如果resultmapping设置了关联查询,也就是association或者collection配置了select,那么就要通过关联语句来查询结果,并设置到实体类对象的属性中了。如果没配置select,那就简单,直接从resultset中通过列名获取结果。那我们来看看getnestedquerymappingvalue
private object getnestedquerymappingvalue(resultset rs, metaobject metaresultobject, resultmapping propertymapping, resultloadermap lazyloader, string columnprefix) throws sqlexception { // 获取关联查询 id,id = 命名空间 + <association> 的 select 属性值 final string nestedqueryid = propertymapping.getnestedqueryid(); final string property = propertymapping.getproperty(); // 根据 nestedqueryid 获取关联的 mappedstatement final mappedstatement nestedquery = configuration.getmappedstatement(nestedqueryid); //获取关联查询mappedstatement的参数类型 final class<?> nestedqueryparametertype = nestedquery.getparametermap().gettype(); /* * 生成关联查询语句参数对象,参数类型可能是一些包装类,map 或是自定义的实体类, * 具体类型取决于配置信息。以上面的例子为基础,下面分析不同配置对参数类型的影响: * 1. <association column="author_id"> * column 属性值仅包含列信息,参数类型为 author_id 列对应的类型,这里为 integer * * 2. <association column="{id=author_id, name=title}"> * column 属性值包含了属性名与列名的复合信息,mybatis 会根据列名从 resultset 中 * 获取列数据,并将列数据设置到实体类对象的指定属性中,比如: * author{id=1, name="陈浩"} * 或是以键值对 <属性, 列数据> 的形式,将两者存入 map 中。比如: * {"id": 1, "name": "陈浩"} * * 至于参数类型到底为实体类还是 map,取决于关联查询语句的配置信息。比如: * <select id="findauthor"> -> 参数类型为 map * <select id="findauthor" parametertype="author"> -> 参数类型为实体类 */ final object nestedqueryparameterobject = prepareparameterfornestedquery(rs, propertymapping, nestedqueryparametertype, columnprefix); object value = null; if (nestedqueryparameterobject != null) { // 获取 boundsql,这里设置了运行时参数,所以这里是能直接执行的 final boundsql nestedboundsql = nestedquery.getboundsql(nestedqueryparameterobject); final cachekey key = executor.createcachekey(nestedquery, nestedqueryparameterobject, rowbounds.default, nestedboundsql); final class<?> targettype = propertymapping.getjavatype(); if (executor.iscached(nestedquery, key)) { executor.deferload(nestedquery, metaresultobject, property, key, targettype); value = defered; } else { // 创建结果加载器 final resultloader resultloader = new resultloader(configuration, executor, nestedquery, nestedqueryparameterobject, targettype, key, nestedboundsql); // 检测当前属性是否需要延迟加载 if (propertymapping.islazy()) { // 添加延迟加载相关的对象到 loadermap 集合中 lazyloader.addloader(property, metaresultobject, resultloader); value = defered; } else { // 直接执行关联查询 // 如果只是配置关联查询,但是没有开启懒加载,则直接执行关联查询,并返回结果,设置到实体类对象的属性中 value = resultloader.loadresult(); } } } return value; }
下面先来总结一下该方法的逻辑:
- 根据 nestedqueryid 获取 mappedstatement
- 生成参数对象
- 获取 boundsql
- 创建结果加载器 resultloader
- 检测当前属性是否需要进行延迟加载,若需要,则添加延迟加载相关的对象到 loadermap 集合中
- 如不需要延迟加载,则直接通过结果加载器加载结果
以上流程中针对一级缓存的检查是十分有必要的,若缓存命中,可直接取用结果,无需再在执行关联查询 sql。若缓存未命中,接下来就要按部就班执行延迟加载相关逻辑
我们来看一下添加延迟加载相关对象到 loadermap 集合中的逻辑,如下:
public void addloader(string property, metaobject metaresultobject, resultloader resultloader) { // 将属性名转为大写 string upperfirst = getuppercasefirstproperty(property); if (!upperfirst.equalsignorecase(property) && loadermap.containskey(upperfirst)) { throw new executorexception("nested lazy loaded result property '" + property + "' for query id '" + resultloader.mappedstatement.getid() + " already exists in the result map. the leftmost property of all lazy loaded properties must be unique within a result map."); } // 创建 loadpair,并将 <大写属性名,loadpair对象> 键值对添加到 loadermap 中 loadermap.put(upperfirst, new loadpair(property, metaresultobject, resultloader)); }
我们再来回顾一下文章开始的创建实体类
private object createresultobject(resultsetwrapper rsw, resultmap resultmap, resultloadermap lazyloader, string columnprefix) throws sqlexception { this.useconstructormappings = false; final list<class<?>> constructorargtypes = new arraylist<class<?>>(); final list<object> constructorargs = new arraylist<object>(); // 调用重载方法创建实体类对象 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) { // 如果开启了延迟加载,则为 resultobject 生成代理类,如果仅仅是配置的关联查询,没有开启延迟加载,是不会创建代理类 if (propertymapping.getnestedqueryid() != null && propertymapping.islazy()) { /* * 创建代理类,默认使用 javassist 框架生成代理类。 * 由于实体类通常不会实现接口,所以不能使用 jdk 动态代理 api 为实体类生成代理。 * 并且将lazyloader传进去了 */ resultobject = configuration.getproxyfactory() .createproxy(resultobject, lazyloader, configuration, objectfactory, constructorargtypes, constructorargs); break; } } } this.useconstructormappings = resultobject != null && !constructorargtypes.isempty(); return resultobject; }
如果开启了延迟加载,并且有关联查询,此时是要创建一个代理对象的,将上面存放bondsql的lazyloader和创建的目标对象resultobject 作为参数传进去。
mybatis提供了两个实现类cglibproxyfactory和javassistproxyfactory,分别基于org.javassist:javassist和cglib:cglib进行实现。createproxy方法就是实现懒加载逻辑的核心方法,也是我们分析的目标。
cglibproxyfactory
cglibproxyfactory基于cglib动态代理模式,通过继承父类的方式生成动态代理类。
@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 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); //由cglibproxyfactory生成对象 object enhanced = crateproxy(type, callback, constructorargtypes, constructorargs); //复制属性 propertycopier.copybeanproperties(type, target, enhanced); return enhanced; } static object crateproxy(class<?> type, callback callback, list<class<?>> constructorargtypes, list<object> constructorargs) { enhancer enhancer = new enhancer(); enhancer.setcallback(callback); //设置父类对象 enhancer.setsuperclass(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.setinterfaces(new class[]{writereplaceinterface.class}); } catch (securityexception e) { // nothing to do here } object enhanced; if (constructorargtypes.isempty()) { enhanced = enhancer.create(); } else { class<?>[] typesarray = constructorargtypes.toarray(new class[constructorargtypes.size()]); object[] valuesarray = constructorargs.toarray(new object[constructorargs.size()]); enhanced = enhancer.create(typesarray, valuesarray); } return enhanced; }
可以看到,初始化enhancer,并调用构造方法,生成对象。从enhancer.setsuperclass(type);
也能看出cglib采用的是继承父类的方式。
enhancedresultobjectproxyimpl
enhancedresultobjectproxyimpl实现了methodinterceptor接口,此接口是cglib拦截目标对象方法的入口,对目标对象方法的调用都会通过此接口的intercept的方法。
@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)) { object original; if (constructorargtypes.isempty()) { original = objectfactory.create(type); } else { original = objectfactory.create(type, constructorargtypes, constructorargs); } propertycopier.copybeanproperties(type, enhanced, original); if (lazyloader.size() > 0) { return new cglibserialstateholder(original, lazyloader.getproperties(), objectfactory, constructorargtypes, constructorargs); } else { return original; } } else { if (lazyloader.size() > 0 && !finalize_method.equals(methodname)) { /* * 如果 aggressive 为 true,或触发方法(比如 equals,hashcode 等)被调用, * 则加载所有的所有延迟加载的数据 */ if (aggressive || lazyloadtriggermethods.contains(methodname)) { lazyloader.loadall(); } else if (propertynamer.issetter(methodname)) { // 如果使用者显示调用了 setter 方法,则将相应的延迟加载类从 loadermap 中移除 final string property = propertynamer.methodtoproperty(methodname); lazyloader.remove(property); // 检测使用者是否调用 getter 方法 } else if (propertynamer.isgetter(methodname)) { final string property = propertynamer.methodtoproperty(methodname); if (lazyloader.hasloader(property)) { // 执行延迟加载逻辑 lazyloader.load(property); } } } } } //执行原方法(即父类方法) return methodproxy.invokesuper(enhanced, args); } catch (throwable t) { throw exceptionutil.unwrapthrowable(t); } }
完整的代码
import java.lang.reflect.method; import java.util.list; import java.util.map; import java.util.properties; import java.util.set; import net.sf.cglib.proxy.callback; import net.sf.cglib.proxy.enhancer; import net.sf.cglib.proxy.methodinterceptor; import net.sf.cglib.proxy.methodproxy; import org.apache.ibatis.executor.loader.abstractenhanceddeserializationproxy; import org.apache.ibatis.executor.loader.abstractserialstateholder; import org.apache.ibatis.executor.loader.proxyfactory; import org.apache.ibatis.executor.loader.resultloadermap; import org.apache.ibatis.executor.loader.writereplaceinterface; import org.apache.ibatis.io.resources; import org.apache.ibatis.logging.log; import org.apache.ibatis.logging.logfactory; import org.apache.ibatis.reflection.exceptionutil; import org.apache.ibatis.reflection.factory.objectfactory; import org.apache.ibatis.reflection.property.propertycopier; import org.apache.ibatis.reflection.property.propertynamer; import org.apache.ibatis.session.configuration; /** * cglib代理工厂类,实现延迟加载属性 * @author clinton begin */ public class cglibproxyfactory implements proxyfactory { /** * finalize方法 */ private static final string finalize_method = "finalize"; /** * writereplace方法 */ private static final string write_replace_method = "writereplace"; /** * 加载enhancer,这个是cglib的入口 */ public cglibproxyfactory() { try { resources.classforname("net.sf.cglib.proxy.enhancer"); } catch (throwable e) { throw new illegalstateexception("cannot enable lazy loading because cglib is not available. add cglib to your classpath.", e); } } /** * 创建代理对象 * @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); } /** * 创建一个反序列化代理 * @param target 目标 * @param unloadedproperties * @param objectfactory 对象工厂 * @param constructorargtypes 构造函数类型数组 * @param constructorargs 构造函数值 * @return */ public object createdeserializationproxy(object target, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { return enhanceddeserializationproxyimpl.createproxy(target, unloadedproperties, objectfactory, constructorargtypes, constructorargs); } @override public void setproperties(properties properties) { // not implemented } /** * 返回代理对象, 这个代理对象在调用任何方法都会调用本类的intercept方法 * enhancer 认为这个就是自定义类的工厂,比如这个类需要实现什么接口 * @param type 目标类型 * @param callback 结果对象代理实现类,当中有invoke回调方法 * @param constructorargtypes 构造函数类型数组 * @param constructorargs 构造函数对应字段的值数组 * @return */ static object crateproxy(class<?> type, callback callback, list<class<?>> constructorargtypes, list<object> constructorargs) { // enhancer 配置调节代理对象的一些参数 // 设置回调方法 // 设置超类 //判断当传入目标类型是否有writereplace方法,没有则配置一个有writereplace方法的接口(序列化写出) enhancer enhancer = new enhancer(); enhancer.setcallback(callback); enhancer.setsuperclass(type); try { type.getdeclaredmethod(write_replace_method); // objectoutputstream will call writereplace of objects returned by writereplace if (logholder.log.isdebugenabled()) { logholder.log.debug(write_replace_method + " method was found on bean " + type + ", make sure it returns this"); } } catch (nosuchmethodexception e) { //这个enhancer增加一个writereplaceinterface接口 enhancer.setinterfaces(new class[]{writereplaceinterface.class}); } catch (securityexception e) { // nothing to do here } //根据构造函数创建一个对象 //无参构造 //有参构造 object enhanced; if (constructorargtypes.isempty()) { enhanced = enhancer.create(); } else { class<?>[] typesarray = constructorargtypes.toarray(new class[constructorargtypes.size()]); object[] valuesarray = constructorargs.toarray(new object[constructorargs.size()]); enhanced = enhancer.create(typesarray, valuesarray); } return enhanced; } /** * 结果对象代理实现类, * 它实现方法拦截器的intercept方法 */ private static class enhancedresultobjectproxyimpl implements methodinterceptor { private final class<?> type; private final resultloadermap lazyloader; private final boolean aggressive; private final set<string> lazyloadtriggermethods; private final objectfactory objectfactory; private final list<class<?>> constructorargtypes; private final list<object> constructorargs; /** * 代理对象创建 * @param type 目标class类型 * @param lazyloader 延迟加载器 * @param configuration 配置信息 * @param objectfactory 对象工厂 * @param constructorargtypes 构造函数类型数组 * @param constructorargs 构造函数值数组 */ 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; } /** * 创建代理对象, 将源对象值赋值给代理对象 * @param target 目标对象 * @param lazyloader 延迟加载器 * @param configuration 配置对象 * @param objectfactory 对象工厂 * @param constructorargtypes 构造函数类型数组 * @param constructorargs 构造函数值数组 * @return */ public static object createproxy(object target, resultloadermap lazyloader, configuration configuration, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { //获取目标的类型 //创建一个结果对象代理实现类(它实现cglib的methodinterface接口,完成回调作用invoke方法) 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 { // 同步获取延迟加载对象 // 如果是执行writereplace方法(序列化写出) // 实例化一个目标对象的实例 synchronized (lazyloader) { if (write_replace_method.equals(methodname)) { object original; if (constructorargtypes.isempty()) { original = objectfactory.create(type); } else { original = objectfactory.create(type, constructorargtypes, constructorargs); } // 将enhanced中的属性复制到orignal对象中 // 如果延迟加载数量>0, propertycopier.copybeanproperties(type, enhanced, original); if (lazyloader.size() > 0) { return new cglibserialstateholder(original, lazyloader.getproperties(), objectfactory, constructorargtypes, constructorargs); } else { return original; } } else { //不是writereplace方法 // 延迟加载长度大于0, 且不是finalize方法 // configuration配置延迟加载参数,延迟加载触发的方法包含这个方法 // 延迟加载所有数据 if (lazyloader.size() > 0 && !finalize_method.equals(methodname)) { if (aggressive || lazyloadtriggermethods.contains(methodname)) { lazyloader.loadall(); // setter方法,直接移除 } else if (propertynamer.issetter(methodname)) { final string property = propertynamer.methodtoproperty(methodname); lazyloader.remove(property); // getter方法, 加载该属性 } else if (propertynamer.isgetter(methodname)) { final string property = propertynamer.methodtoproperty(methodname); if (lazyloader.hasloader(property)) { lazyloader.load(property); } } } } } return methodproxy.invokesuper(enhanced, args); } catch (throwable t) { throw exceptionutil.unwrapthrowable(t); } } } /** * 他继承抽象反序列化代理和实现了方法拦截 */ private static class enhanceddeserializationproxyimpl extends abstractenhanceddeserializationproxy implements methodinterceptor { private enhanceddeserializationproxyimpl(class<?> type, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { super(type, unloadedproperties, objectfactory, constructorargtypes, constructorargs); } /** * 创建代理对象 * @param target * @param unloadedproperties * @param objectfactory * @param constructorargtypes * @param constructorargs * @return */ public static object createproxy(object target, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { final class<?> type = target.getclass(); enhanceddeserializationproxyimpl callback = new enhanceddeserializationproxyimpl(type, unloadedproperties, objectfactory, constructorargtypes, constructorargs); object enhanced = crateproxy(type, callback, constructorargtypes, constructorargs); propertycopier.copybeanproperties(type, target, enhanced); return enhanced; } @override public object intercept(object enhanced, method method, object[] args, methodproxy methodproxy) throws throwable { final object o = super.invoke(enhanced, method, args); return o instanceof abstractserialstateholder ? o : methodproxy.invokesuper(o, args); } @override protected abstractserialstateholder newserialstateholder(object userbean, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { return new cglibserialstateholder(userbean, unloadedproperties, objectfactory, constructorargtypes, constructorargs); } } }
如上,代理方法首先会检查 aggressive 是否为 true,如果不满足,再去检查 lazyloadtriggermethods 是否包含当前方法名。这里两个条件只要一个为 true,当前实体类中所有需要延迟加载。aggressive 和 lazyloadtriggermethods 两个变量的值取决于下面的配置。
<setting name="aggressivelazyloading" value="false"/> <setting name="lazyloadtriggermethods" value="equals,hashcode"/>
然后代理逻辑会检查使用者是不是调用了实体类的 setter 方法,如果调用了,就将该属性对应的 loadpair 从 loadermap 中移除。为什么要这么做呢?答案是:使用者既然手动调用 setter 方法,说明使用者想自定义某个属性的值。此时,延迟加载逻辑不应该再修改该属性的值,所以这里从 loadermap 中移除属性对于的 loadpair。
最后如果使用者调用的是某个属性的 getter 方法,且该属性配置了延迟加载,此时延迟加载逻辑就会被触发。那接下来,我们来看看延迟加载逻辑是怎样实现的的。
public boolean load(string property) throws sqlexception { // 从 loadermap 中移除 property 所对应的 loadpair loadpair pair = loadermap.remove(property.touppercase(locale.english)); if (pair != null) { // 加载结果 pair.load(); return true; } return false; } public void load(final object userobject) throws sqlexception { /* * 调用 resultloader 的 loadresult 方法加载结果, * 并通过 metaresultobject 设置结果到实体类对象中 */ this.metaresultobject.setvalue(property, this.resultloader.loadresult()); } public object loadresult() throws sqlexception { // 执行关联查询 list<object> list = selectlist(); // 抽取结果 resultobject = resultextractor.extractobjectfromlist(list, targettype); return resultobject; } private <e> list<e> selectlist() throws sqlexception { executor localexecutor = executor; if (thread.currentthread().getid() != this.creatorthreadid || localexecutor.isclosed()) { localexecutor = newexecutor(); } try { // 通过 executor 就行查询,这个之前已经分析过了 // 这里的parameterobject和boundsql就是我们之前存放在loadpair中的,现在直接拿来执行了 return localexecutor.<e>query(mappedstatement, parameterobject, rowbounds.default, executor.no_result_handler, cachekey, boundsql); } finally { if (localexecutor != executor) { localexecutor.close(false); } } }
好了,延迟加载我们基本已经讲清楚了,我们介绍一下另外的一种代理方式
javassistproxyfactory
javassistproxyfactory使用的是javassist方式,直接修改class文件的字节码格式。
import java.lang.reflect.method; import java.util.list; import java.util.map; import java.util.properties; import java.util.set; import javassist.util.proxy.methodhandler; import javassist.util.proxy.proxy; import javassist.util.proxy.proxyfactory; import org.apache.ibatis.executor.executorexception; import org.apache.ibatis.executor.loader.abstractenhanceddeserializationproxy; import org.apache.ibatis.executor.loader.abstractserialstateholder; import org.apache.ibatis.executor.loader.resultloadermap; import org.apache.ibatis.executor.loader.writereplaceinterface; import org.apache.ibatis.io.resources; import org.apache.ibatis.logging.log; import org.apache.ibatis.logging.logfactory; import org.apache.ibatis.reflection.exceptionutil; import org.apache.ibatis.reflection.factory.objectfactory; import org.apache.ibatis.reflection.property.propertycopier; import org.apache.ibatis.reflection.property.propertynamer; import org.apache.ibatis.session.configuration; /**javassistproxy字节码生成代理 * 1.创建一个代理对象然后将目标对象的值赋值给代理对象,这个代理对象是可以实现其他的接口 * 2. javassistproxyfactory实现proxyfactory接口createproxy(创建代理对象的方法) * @author eduardo macarron */ public class javassistproxyfactory implements org.apache.ibatis.executor.loader.proxyfactory { /** * finalize方法(垃圾回收) */ private static final string finalize_method = "finalize"; /** * writereplace(序列化写出方法) */ private static final string write_replace_method = "writereplace"; /** * 加载proxyfactory, 也就是javassistproxy的入口 */ public javassistproxyfactory() { try { resources.classforname("javassist.util.proxy.proxyfactory"); } catch (throwable e) { throw new illegalstateexception("cannot enable lazy loading because javassist is not available. add javassist to your classpath.", e); } } /** * 创建代理 * @param target 目标对象 * @param lazyloader 延迟加载map集合(那些属性是需要延迟加载的) * @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); } public object createdeserializationproxy(object target, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { return enhanceddeserializationproxyimpl.createproxy(target, unloadedproperties, objectfactory, constructorargtypes, constructorargs); } @override public void setproperties(properties properties) { // not implemented } /** * 获取代理对象, 也就是说在执行方法之前首先调用methodhanlder的invoke方法 * @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.setsuperclass(type); //判断是否有writereplace方法,如果没有将这个代理对象实现writereplaceinterface接口,这个接口只有一个writereplace方法 try { type.getdeclaredmethod(write_replace_method); // objectoutputstream will call writereplace of objects returned by writereplace if (logholder.log.isdebugenabled()) { logholder.log.debug(write_replace_method + " method was found on bean " + type + ", make sure it returns this"); } } catch (nosuchmethodexception e) { enhancer.setinterfaces(new class[]{writereplaceinterface.class}); } catch (securityexception 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. cause: " + e, e); } // 设置回调对象 ((proxy) enhanced).sethandler(callback); return enhanced; } /** * 实现javassist的methodhandler接口, 相对于cglib的methodinterceptor * 他们接口的方法名也是不一样的,javassist的是invoke, 而cglib是intercept,叫法不同,实现功能是一样的 */ private static class enhancedresultobjectproxyimpl implements methodhandler { /** * 目标类型 */ private final class<?> type; /** * 延迟加载map集合 */ private final resultloadermap lazyloader; /** * 是否配置延迟加载 */ private final boolean aggressive; /** * 延迟加载触发的方法 */ private final set<string> lazyloadtriggermethods; /** * 对象工厂 */ private final objectfactory objectfactory; /** * 构造函数类型数组 */ private final list<class<?>> constructorargtypes; /** * 构造函数类型的值数组 */ private final list<object> constructorargs; /** * 构造函数私有化了 * @param type * @param lazyloader * @param configuration * @param objectfactory * @param constructorargtypes * @param constructorargs */ 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) { // 获取目标类型 // 创建一个enhancedresultobjectproxyimpl对象,回调对象 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 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)) { //如果方法是writereplace object original; if (constructorargtypes.isempty()) { original = objectfactory.create(type); } else { original = objectfactory.create(type, constructorargtypes, constructorargs); } propertycopier.copybeanproperties(type, enhanced, original); if (lazyloader.size() > 0) { return new javassistserialstateholder(original, lazyloader.getproperties(), objectfactory, constructorargtypes, constructorargs); } else { return original; } } else { //不是writereplace方法 // 延迟加载长度大于0, 且不是finalize方法 // configuration配置延迟加载参数,延迟加载触发的方法包含这个方法 // 延迟加载所有数据 if (lazyloader.size() > 0 && !finalize_method.equals(methodname)) { if (aggressive || lazyloadtriggermethods.contains(methodname)) { lazyloader.loadall(); } else if (propertynamer.issetter(methodname)) { final string property = propertynamer.methodtoproperty(methodname); lazyloader.remove(property); } else if (propertynamer.isgetter(methodname)) { final string property = propertynamer.methodtoproperty(methodname); if (lazyloader.hasloader(property)) { lazyloader.load(property); } } } } } return methodproxy.invoke(enhanced, args); } catch (throwable t) { throw exceptionutil.unwrapthrowable(t); } } } private static class enhanceddeserializationproxyimpl extends abstractenhanceddeserializationproxy implements methodhandler { private enhanceddeserializationproxyimpl(class<?> type, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { super(type, unloadedproperties, objectfactory, constructorargtypes, constructorargs); } public static object createproxy(object target, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { final class<?> type = target.getclass(); enhanceddeserializationproxyimpl callback = new enhanceddeserializationproxyimpl(type, unloadedproperties, objectfactory, constructorargtypes, constructorargs); object enhanced = crateproxy(type, callback, constructorargtypes, constructorargs); propertycopier.copybeanproperties(type, target, enhanced); return enhanced; } @override public object invoke(object enhanced, method method, method methodproxy, object[] args) throws throwable { final object o = super.invoke(enhanced, method, args); return o instanceof abstractserialstateholder ? o : methodproxy.invoke(o, args); } @override protected abstractserialstateholder newserialstateholder(object userbean, map<string, resultloadermap.loadpair> unloadedproperties, objectfactory objectfactory, list<class<?>> constructorargtypes, list<object> constructorargs) { return new javassistserialstateholder(userbean, unloadedproperties, objectfactory, constructorargtypes, constructorargs); } } private static class logholder { private static final log log = logfactory.getlog(javassistproxyfactory.class); } }
注释已经很清楚了,我就不累述了