相关案例参考:https://www.jianshu.com/p/ff5e1b3ce9e4
测试注意
打断的测试懒加载的时候一直失效,解决办法是在配置文件中加入
具体原因可参考:https://blog.csdn.net/mingtian625/article/details/46846985
懒加载原理
原理其实特别简单,就是在分析DO的成员变量的时候,发现如果有懒加载的配置,如:fetchType="lazy",则把DO转化成代理类返回。并把懒加载相关对象放到ResultLoaderMap中存起来。当调用相应get方法获取懒加载变量的时候则根据代理类去执行sql获取。
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
ResultLoaderMap lazyLoader = new ResultLoaderMap();
//解析resultmap也就是返回的对象成员变量
Object rowValue = this.createResultObject(rsw, resultMap, lazyLoader, (String)null);
if (rowValue != null && !this.hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
MetaObject metaObject = this.configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (this.shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = this.applyAutomaticMappings(rsw, resultMap, metaObject, (String)null) || foundValues;
}
foundValues = this.applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, (String)null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = !foundValues && !this.configuration.isReturnInstanceForEmptyRow() ? null : rowValue;
}
return rowValue;
}
转化对象为代理默认CglibProxyFactory工场配置,可配置为JavassistProxy
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
this.useConstructorMappings = false;
List> constructorArgTypes = new ArrayList();
List
后续再调用属性赋值applyPropertyMappings-》getPropertyMappingValue
private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
//代理分支
if (propertyMapping.getNestedQueryId() != null) {
return this.getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
} else if (propertyMapping.getResultSet() != null) {
this.addPendingChildRelation(rs, metaResultObject, propertyMapping);
return DEFERED;
} else {
TypeHandler> typeHandler = propertyMapping.getTypeHandler();
String column = this.prependPrefix(propertyMapping.getColumn(), columnPrefix);
return typeHandler.getResult(rs, column);
}
}
private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
....
Object value = null;
if (nestedQueryParameterObject != null) {
BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
CacheKey key = this.executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
Class> targetType = propertyMapping.getJavaType();
if (this.executor.isCached(nestedQuery, key)) {
this.executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
value = DEFERED;
} else {
ResultLoader resultLoader = new ResultLoader(this.configuration, this.executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
if (propertyMapping.isLazy()) {
//将懒加载相关信息存储起来
lazyLoader.addLoader(property, metaResultObject, resultLoader);
value = DEFERED;
} else {
value = resultLoader.loadResult();
}
}
}
return value;
}
最后在调用get方法的时候,通过代理:
{
String methodName = method.getName();
try {
ResultLoaderMap var6 = this.lazyLoader;
synchronized(this.lazyLoader) {
if ("writeReplace".equals(methodName)) {
Object original;
if (this.constructorArgTypes.isEmpty()) {
original = this.objectFactory.create(this.type);
} else {
original = this.objectFactory.create(this.type, this.constructorArgTypes, this.constructorArgs);
}
PropertyCopier.copyBeanProperties(this.type, enhanced, original);
if (this.lazyLoader.size() > 0) {
return new JavassistSerialStateHolder(original, this.lazyLoader.getProperties(), this.objectFactory, this.constructorArgTypes, this.constructorArgs);
}
return original;
}
if (this.lazyLoader.size() > 0 && !"finalize".equals(methodName)) {
if (!this.aggressive && !this.lazyLoadTriggerMethods.contains(methodName)) {
if (PropertyNamer.isGetter(methodName)) {
String property = PropertyNamer.methodToProperty(methodName);
//去加载调用查询方法,返回结果
if (this.lazyLoader.hasLoader(property)) {
this.lazyLoader.load(property);
}
}
} else {
this.lazyLoader.loadAll();
}
}
}
return methodProxy.invoke(enhanced, args);
} catch (Throwable var10) {
throw ExceptionUtil.unwrapThrowable(var10);
}
}