上一篇文章咱们已经将SQL发送到了数据库,并返回了ResultSet,接下来就是将结果集 ResultSet 自动映射成实体类对象。这样使用者就无需再手动操做结果集,并将数据填充到实体类对象中。这可大大下降开发的工做量,提升工做效率。html
咱们来看看上次看源码的位置java
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方法apache
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的ResultListsession
MyBatis 默认提供了 RowBounds 用于分页,从上面的代码中能够看出,这并不是是一个高效的分页方式,是查出全部的数据,进行内存分页。除了使用 RowBounds,还可使用一些第三方分页插件进行分页。咱们后面文章来说,咱们来看关键代码getRowValue,处理一行数据app
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中并无配置ide
根据 <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 中。
接下来分析一下 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; }
下面先来总结一下该方法的逻辑:
以上流程中针对一级缓存的检查是十分有必要的,若缓存命中,可直接取用结果,无需再在执行关联查询 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基于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使用的是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); } }
注释已经很清楚了,我就不累述了