mybatis懒加载的源码分析

相关案例参考: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 constructorArgs = new ArrayList();
        Object resultObject = this.createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
        if (resultObject != null && !this.hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
            List propertyMappings = resultMap.getPropertyResultMappings();
            Iterator var9 = propertyMappings.iterator();

            while(var9.hasNext()) {
                ResultMapping propertyMapping = (ResultMapping)var9.next();
                //符合懒加载,把对象转化成代理类
                if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
                    resultObject = this.configuration.getProxyFactory().createProxy(resultObject, lazyLoader, this.configuration, this.objectFactory, constructorArgTypes, constructorArgs);
                    break;
                }
            }
        }

        this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty();
        return resultObject;
    }
 
 

后续再调用属性赋值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);
            }
        }

你可能感兴趣的:(mybatis懒加载的源码分析)