Mybatis源碼分析——結(jié)果集ResultSet自動(dòng)映射成實(shí)體類對(duì)象

前言

上一篇文章我們已經(jīng)將SQL發(fā)送到了數(shù)據(jù)庫(kù)撬碟,并返回了ResultSet岂傲,接下來(lái)就是將結(jié)果集 ResultSet 自動(dòng)映射成實(shí)體類對(duì)象扫沼。這樣使用者就無(wú)需再手動(dòng)操作結(jié)果集叁温,并將數(shù)據(jù)填充到實(shí)體類對(duì)象中江掩。這可大大降低開發(fā)的工作量学辱,提高工作效率。

映射結(jié)果入口

我們來(lái)看看上次看源碼的位置

public class PreparedStatementHandler extends BaseStatementHandler {

    @Override
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        //執(zhí)行數(shù)據(jù)庫(kù)SQL
        ps.execute();
        //進(jìn)行resultSet自動(dòng)映射
        return resultSetHandler.<E> handleResultSets(ps);
    }
}

結(jié)果集的處理入口方法是 handleResultSets

public class DefaultResultSetHandler implements ResultSetHandler {

    public List<Object> handleResultSets(Statement stmt) throws SQLException {
        ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

        final List<Object> multipleResults = new ArrayList<Object>();

        int resultSetCount = 0;
        //獲取第一個(gè)ResultSet,通常只會(huì)有一個(gè)
        ResultSetWrapper rsw = getFirstResultSet(stmt);
        
        //從配置中讀取對(duì)應(yīng)的ResultMap频敛,通常也只會(huì)有一個(gè)项郊,設(shè)置多個(gè)是通過(guò)逗號(hào)來(lái)分隔,我們平時(shí)有這樣設(shè)置嗎斟赚?
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        int resultMapCount = resultMaps.size();
        validateResultMapsCount(rsw, resultMapCount);
        while (rsw != null && resultMapCount > resultSetCount) {
            ResultMap resultMap = resultMaps.get(resultSetCount);
            // 處理結(jié)果集
            handleResultSet(rsw, resultMap, multipleResults, null);
            //獲取結(jié)果集的下一個(gè)結(jié)果
            rsw = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
        }
        
        String[] resultSets = mappedStatement.getResultSets();
        if (resultSets != null) {
            //和resultMaps的遍歷處理類似
            while (rsw != null && resultSetCount < resultSets.length) {
            ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
                if (parentMapping != null) {
                    String nestedResultMapId = parentMapping.getNestedResultMapId();
                    ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
                    handleResultSet(rsw, resultMap, null, parentMapping);
                }
                rsw = getNextResultSet(stmt);
                cleanUpAfterHandlingResultSet();
                resultSetCount++;
            }
        }

        return collapseSingleResultList(multipleResults);
    }
}

在實(shí)際運(yùn)行過(guò)程中着降,通常情況下一個(gè)Sql語(yǔ)句只返回一個(gè)結(jié)果集,對(duì)多個(gè)結(jié)果集的情況不做分析 拗军。實(shí)際很少用到任洞。繼續(xù)看handleResultSet方法

public class DefaultResultSetHandler implements ResultSetHandler {

    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) {
                    // 創(chuàng)建默認(rèn)的結(jié)果處理器
                    DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
                    // 處理結(jié)果集的行數(shù)據(jù)
                    handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
                    // 將結(jié)果加入multipleResults中
                    multipleResults.add(defaultResultHandler.getResultList());
                } else {
                    handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
                }
            }
        } finally {
            // issue #228 (close resultsets)
            closeResultSet(rsw.getResultSet());
        }
    }
}

通過(guò)handleRowValues 映射ResultSet結(jié)果,最后映射的結(jié)果會(huì)在defaultResultHandler的ResultList集合中发侵,最后將結(jié)果加入到multipleResults中就可以返回了交掏,我們繼續(xù)跟進(jìn)handleRowValues這個(gè)核心方法

public class DefaultResultSetHandler implements ResultSetHandler {

    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 {
            // 處理簡(jiǎn)單映射
            handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        }
    }
}

我們可以通過(guò)resultMap.hasNestedResultMaps()知道查詢語(yǔ)句是否是嵌套查詢,如果resultMap中包含<association> 和 <collection>且其select屬性不為空刃鳄,則為嵌套查詢盅弛。本文先分析簡(jiǎn)單的映射

public class DefaultResultSetHandler implements ResultSetHandler {

    private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
        DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
        // 根據(jù) RowBounds 定位到指定行記錄
        skipRows(rsw.getResultSet(), rowBounds);
        // ResultSet是一個(gè)集合,很有可能我們查詢的就是一個(gè)List叔锐,這就就每條數(shù)據(jù)遍歷處理
        while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
            ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
            // 從 resultSet 中獲取結(jié)果
            Object rowValue = getRowValue(rsw, discriminatedResultMap);
            // 存儲(chǔ)結(jié)果到resultHandler的ResultList琉朽,最后ResultList加入multipleResults中返回
            storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
    }
}

我們查詢的結(jié)果很有可能是一個(gè)集合区赵,所以這里要遍歷集合锣夹,每條結(jié)果單獨(dú)進(jìn)行映射是嗜,最后映射的結(jié)果加入到resultHandler的ResultList

MyBatis 默認(rèn)提供了 RowBounds 用于分頁(yè),從上面的代碼中可以看出步责,這并非是一個(gè)高效的分頁(yè)方式返顺,是查出所有的數(shù)據(jù),進(jìn)行內(nèi)存分頁(yè)蔓肯。除了使用 RowBounds遂鹊,還可以使用一些第三方分頁(yè)插件進(jìn)行分頁(yè)。我們后面文章來(lái)講蔗包,我們來(lái)看關(guān)鍵代碼getRowValue稿辙,處理一行數(shù)據(jù)

public class DefaultResultSetHandler implements ResultSetHandler {

    private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
        // 這個(gè)Map是用來(lái)存儲(chǔ)延遲加載的BountSql的,我們下面來(lái)看
        final ResultLoaderMap lazyLoader = new ResultLoaderMap();
        // 創(chuàng)建實(shí)體類對(duì)象气忠,比如 User 對(duì)象
        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)) {
                //自動(dòng)映射,結(jié)果集中有的column邻储,但resultMap中并沒(méi)有配置  
                foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
            }
            // 根據(jù) <resultMap> 節(jié)點(diǎn)中配置的映射關(guān)系進(jìn)行映射
            foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
            foundValues = lazyLoader.size() > 0 || foundValues;
            rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
        }
        return rowValue;
    }
}

重要的邏輯已經(jīng)注釋出來(lái)了。分別如下:

  • 1旧噪、創(chuàng)建實(shí)體類對(duì)象吨娜。
  • 2、自動(dòng)映射結(jié)果集中有的column淘钟,但resultMap中并沒(méi)有配置宦赠。
  • 3、根據(jù) <resultMap> 節(jié)點(diǎn)中配置的映射關(guān)系進(jìn)行映射米母。

創(chuàng)建實(shí)體類對(duì)象

我們想將查詢結(jié)果映射成實(shí)體類對(duì)象勾扭,第一步當(dāng)然是要?jiǎng)?chuàng)建實(shí)體類對(duì)象了,下面我們來(lái)看一下 MyBatis 創(chuàng)建實(shí)體類對(duì)象的過(guò)程铁瞒。

public class DefaultResultSetHandler implements ResultSetHandler {

    private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
        this.useConstructorMappings = false; // reset previous mapping result
        final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
        final List<Object> constructorArgs = new ArrayList<Object>();
        
        // 調(diào)用重載方法創(chuàng)建實(shí)體類對(duì)象
        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) {
                // issue gcode #109 && issue #149
                // 如果開啟了延遲加載妙色,則為 resultObject 生成代理類,如果僅僅是配置的關(guān)聯(lián)查詢慧耍,沒(méi)有開啟延遲加載身辨,是不會(huì)創(chuàng)建代理類
                if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
                    /*
                     * 創(chuàng)建代理類,默認(rèn)使用 Javassist 框架生成代理類芍碧。
                     * 由于實(shí)體類通常不會(huì)實(shí)現(xiàn)接口煌珊,所以不能使用 JDK 動(dòng)態(tài)代理 API 為實(shí)體類生成代理。
                     * 并且將lazyLoader傳進(jìn)去了
                     */
                    resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
                    break;
                }
            }
        }
        this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
        return resultObject;
    }
}

我們先來(lái)看 createResultObject 重載方法的邏輯

public class DefaultResultSetHandler implements ResultSetHandler {

    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()) {
            // 通過(guò) ObjectFactory 調(diào)用目標(biāo)類的默認(rèn)構(gòu)造方法創(chuàng)建實(shí)例
            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 會(huì)通過(guò) ObjectFactory 調(diào)用默認(rèn)構(gòu)造方法創(chuàng)建實(shí)體類對(duì)象定庵。看看是如何創(chuàng)建的

public class DefaultObjectFactory implements ObjectFactory, Serializable {

    @Override
    public <T> T create(Class<T> type) {
        return create(type, null, null);
    }
    
    @Override
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        Class<?> classToCreate = resolveInterface(type);
        // we know types are assignable
        return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
    }
    
    private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        try {
            Constructor<T> constructor;
            if (constructorArgTypes == null || constructorArgs == null) {
                constructor = type.getDeclaredConstructor();
                if (!constructor.isAccessible()) {
                    constructor.setAccessible(true);
                }
                return constructor.newInstance();
            }
            //通過(guò)反射獲取構(gòu)造器
            constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
            if (!constructor.isAccessible()) {
                constructor.setAccessible(true);
            }
            //通過(guò)構(gòu)造器來(lái)實(shí)例化對(duì)象
            return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
        } catch (Exception e) {
            StringBuilder argTypes = new StringBuilder();
            if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
                for (Class<?> argType : constructorArgTypes) {
                    argTypes.append(argType.getSimpleName());
                    argTypes.append(",");
                }
                argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
            }
            StringBuilder argValues = new StringBuilder();
            if (constructorArgs != null && !constructorArgs.isEmpty()) {
                for (Object argValue : constructorArgs) {
                    argValues.append(String.valueOf(argValue));
                    argValues.append(",");
                }
                argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
            }
            throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
        }
    }
}

很簡(jiǎn)單踪危,就是通過(guò)反射創(chuàng)建對(duì)象

結(jié)果集映射

映射結(jié)果集分為兩種情況:

  • 1蔬浙、是自動(dòng)映射(結(jié)果集有但在resultMap里沒(méi)有配置的字段),在實(shí)際應(yīng)用中陨倡,都會(huì)使用自動(dòng)映射敛滋,減少配置的工作。自動(dòng)映射在Mybatis中也是默認(rèn)開啟的兴革。
  • 2绎晃、是映射ResultMap中配置的。

我們分這兩者映射來(lái)看

自動(dòng)映射

foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;

public class DefaultResultSetHandler implements ResultSetHandler {

    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) {
                // 通過(guò) TypeHandler 從結(jié)果集中獲取指定列的數(shù)據(jù)
                final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
                if (value != null) {
                    foundValues = true;
                }
                if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
                    // gcode issue #377, call setter on nulls (value is not 'found')
                    // 通過(guò)元信息對(duì)象設(shè)置 value 到實(shí)體類對(duì)象的指定字段上
                    metaObject.setValue(mapping.property, value);
                }
            }
        }
        return foundValues;
    }
}

首先是獲取 UnMappedColumnAutoMapping 集合杂曲,然后遍歷該集合庶艾,并通過(guò) TypeHandler 從結(jié)果集中獲取數(shù)據(jù),最后再將獲取到的數(shù)據(jù)設(shè)置到實(shí)體類對(duì)象中擎勘。

UnMappedColumnAutoMapping 用于記錄未配置在 <resultMap> 節(jié)點(diǎn)中的映射關(guān)系咱揍。它的代碼如下:

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;
    }
}

僅用于記錄映射關(guān)系。下面看一下獲取 UnMappedColumnAutoMapping 集合的過(guò)程棚饵,如下:

public class DefaultResultSetHandler implements ResultSetHandler {

    private final Configuration configuration;
    private final MappedStatement mappedStatement;
    
    private final TypeHandlerRegistry typeHandlerRegistry;

    private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<String, List<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()) {
                    // When columnPrefix is specified,
                    // ignore columns without the prefix.
                    if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
                        propertyName = columnName.substring(columnPrefix.length());
                    } else {
                        continue;
                    }
                }
                
                // 將下劃線形式的列名轉(zhuǎn)成駝峰式煤裙,比如 AUTHOR_NAME -> authorName
                final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
                if (property != null && metaObject.hasSetter(property)) {
                    // 檢測(cè)當(dāng)前屬性是否存在于 resultMap 中
                    if (resultMap.getMappedProperties().contains(property)) {
                        continue;
                    }
                    
                    // 獲取屬性對(duì)于的類型
                    final Class<?> propertyType = metaObject.getSetterType(property);
                    if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
                        final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
                        // 封裝上面獲取到的信息到 UnMappedColumnAutoMapping 對(duì)象中
                        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;
    }
}

先來(lái)看看從 ResultSetWrapper 中獲取未配置在 <resultMap> 中的列名
即跟進(jìn)

public class ResultSetWrapper {

    private final Map<String, List<String>> unMappedColumnNamesMap = new HashMap<String, List<String>>();

    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 的成員變量,保存了當(dāng)前結(jié)果集中的所有列名
         * 這里是通過(guò)ResultSet中的所有列名來(lái)獲取沒(méi)有在resultMap中配置的列名
         * 意思是后面進(jìn)行自動(dòng)賦值時(shí)硼砰,只賦值查出來(lái)的列名
         */
        for (String columnName : columnNames) {
            final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);
            // 檢測(cè)已映射列名集合中是否包含當(dāng)前列名
            if (mappedColumns.contains(upperColumnName)) {
                mappedColumnNames.add(upperColumnName);
            } else {
                // 將列名存入 unmappedColumnNames 中
                unmappedColumnNames.add(columnName);
            }
        }
        // 緩存列名集合
        mappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), mappedColumnNames);
        unMappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), unmappedColumnNames);
    }
}

首先是從當(dāng)前數(shù)據(jù)集中獲取列名集合且蓬,然后獲取 <resultMap> 中配置的列名集合。之后遍歷數(shù)據(jù)集中的列名集合题翰,并判斷列名是否被配置在了 <resultMap> 節(jié)點(diǎn)中恶阴。若配置了,則表明該列名已有映射關(guān)系豹障,此時(shí)該列名存入 mappedColumnNames 中冯事。若未配置,則表明列名未與實(shí)體類的某個(gè)字段形成映射關(guān)系血公,此時(shí)該列名存入 unmappedColumnNames 中昵仅。

映射result節(jié)點(diǎn)

foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
接下來(lái)分析一下 MyBatis 是如何將結(jié)果集中的數(shù)據(jù)填充到已配置ResultMap映射的實(shí)體類字段中的。

public class DefaultResultSetHandler implements ResultSetHandler {

    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遍歷進(jìn)行映射
        for (ResultMapping propertyMapping : propertyMappings) {
            String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
            if (propertyMapping.getNestedResultMapId() != null) {
                // the user added a column attribute to a nested result map, ignore it
                column = null;
            }
            if (propertyMapping.isCompositeResult()
                || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
                || propertyMapping.getResultSet() != null) {
                // 從結(jié)果集中獲取指定列的數(shù)據(jù)
                Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
                // issue #541 make property optional
                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())) {
                    // gcode issue #377, call setter on nulls (value is not 'found')
                    // 將獲取到的值設(shè)置到實(shí)體類對(duì)象中
                    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) {
            // 獲取關(guān)聯(lián)查詢結(jié)果
            return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
        } else if (propertyMapping.getResultSet() != null) {
            addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
            return DEFERED;
        } else {
            final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
            final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
            // 從 ResultSet 中獲取指定列的值
            return typeHandler.getResult(rs, column);
        }
    }
}

從 ResultMap 獲取映射對(duì)象 ResultMapping 集合岩饼。然后遍歷 ResultMapping 集合,再此過(guò)程中調(diào)用 getPropertyMappingValue 獲取指定指定列的數(shù)據(jù)薛夜,最后將獲取到的數(shù)據(jù)設(shè)置到實(shí)體類對(duì)象中籍茧。

這里和自動(dòng)映射有一點(diǎn)不同,自動(dòng)映射是從直接從ResultSet 中獲取指定列的值梯澜,但是通過(guò)ResultMap多了一種情況寞冯,那就是關(guān)聯(lián)查詢,也可以說(shuō)是延遲查詢晚伙,此關(guān)聯(lián)查詢?nèi)绻麤](méi)有配置延遲加載吮龄,那么就要獲取關(guān)聯(lián)查詢的值,如果配置了延遲加載咆疗,則返回DEFERED漓帚。

關(guān)聯(lián)查詢與延遲加載

我們的查詢經(jīng)常會(huì)碰到一對(duì)一,一對(duì)多的情況午磁,通常我們可以用一條 SQL 進(jìn)行多表查詢完成任務(wù)尝抖。當(dāng)然我們也可以使用關(guān)聯(lián)查詢,將一條 SQL 拆成兩條去完成查詢?nèi)蝿?wù)迅皇。MyBatis 提供了兩個(gè)標(biāo)簽用于支持一對(duì)一和一對(duì)多的使用場(chǎng)景昧辽,分別是 <association> 和 <collection>。下面我來(lái)演示一下如何使用 <association> 完成一對(duì)一的關(guān)聯(lián)查詢登颓。先來(lái)看看實(shí)體類的定義:

/** 作者類 */
@Data
public class Author {
    private Integer id;
    private String name;
    private Integer age;
    private Integer sex;
    private String email;
}

/** 文章類 */
@Data
public class Article {
    private Integer id;
    private String title;
    private String content;
    private Date createTime;
    
    // 一對(duì)一關(guān)系
    private Author author;
}

接下來(lái)看一下 Mapper 接口與映射文件的定義搅荞。

public interface ArticleMapper {
    Article findOne(@Param("id") int id);
    Author findAuthor(@Param("id") int authorId);
}
<mapper namespace="com.yibo.mapper.ArticleMapper">
    <resultMap id="articleResult" type="Article">
        <result property="createTime" column="create_time"/>
        //column 屬性值僅包含列信息,參數(shù)類型為 author_id 列對(duì)應(yīng)的類型,這里為 Integer
        //意思是將author_id做為參數(shù)傳給關(guān)聯(lián)的查詢語(yǔ)句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"/>
<!-- 關(guān)閉積極的加載策略 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 延遲加載的觸發(fā)方法 -->
<setting name="lazyLoadTriggerMethods" value="equals,hashCode"/>

此時(shí)association節(jié)點(diǎn)使用了select指向另外一個(gè)查詢語(yǔ)句咕痛,并且將 author_id作為參數(shù)傳給關(guān)聯(lián)查詢的語(yǔ)句

此時(shí)如果不開啟延遲加載痢甘,那么會(huì)生成兩條SQL,先執(zhí)行findOne暇检,然后通過(guò)findOne的返回結(jié)果做為參數(shù)产阱,執(zhí)行findAuthor語(yǔ)句,并將結(jié)果設(shè)置到author屬性

如果開啟了延遲加載呢块仆?那么只會(huì)執(zhí)行findOne一條SQL,當(dāng)調(diào)用article.getAuthor()方法時(shí)王暗,才會(huì)去執(zhí)行findAuthor進(jìn)行查詢悔据,我們下面來(lái)看看是如何實(shí)現(xiàn)的

我們還是要從上面映射result節(jié)點(diǎn)說(shuō)起

public class DefaultResultSetHandler implements ResultSetHandler {
    
    private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
        if (propertyMapping.getNestedQueryId() != null) {
            // 獲取關(guān)聯(lián)查詢結(jié)果
            return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
        } else if (propertyMapping.getResultSet() != null) {
            addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
            return DEFERED;
        } else {
            final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
            final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
            // 從 ResultSet 中獲取指定列的值
            return typeHandler.getResult(rs, column);
        }
    }
}

我們看到,如果ResultMapping設(shè)置了關(guān)聯(lián)查詢俗壹,也就是association或者collection配置了select科汗,那么就要通過(guò)關(guān)聯(lián)語(yǔ)句來(lái)查詢結(jié)果,并設(shè)置到實(shí)體類對(duì)象的屬性中了绷雏。如果沒(méi)配置select头滔,那就簡(jiǎn)單,直接從ResultSet中通過(guò)列名獲取結(jié)果涎显。那我們來(lái)看看getNestedQueryMappingValue

public class DefaultResultSetHandler implements ResultSetHandler {
    
    private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
      throws SQLException {
        // 獲取關(guān)聯(lián)查詢 id坤检,id = 命名空間 + <association> 的 select 屬性值
        final String nestedQueryId = propertyMapping.getNestedQueryId();
        final String property = propertyMapping.getProperty();
        // 根據(jù) nestedQueryId 獲取關(guān)聯(lián)的 MappedStatement
        final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
        //獲取關(guān)聯(lián)查詢MappedStatement的參數(shù)類型
        final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
        /*
         * 生成關(guān)聯(lián)查詢語(yǔ)句參數(shù)對(duì)象,參數(shù)類型可能是一些包裝類期吓,Map 或是自定義的實(shí)體類早歇,
         * 具體類型取決于配置信息。以上面的例子為基礎(chǔ)讨勤,下面分析不同配置對(duì)參數(shù)類型的影響:
         *   1. <association column="author_id"> 
         *      column 屬性值僅包含列信息箭跳,參數(shù)類型為 author_id 列對(duì)應(yīng)的類型,這里為 Integer
         * 
         *   2. <association column="{id=author_id, name=title}"> 
         *      column 屬性值包含了屬性名與列名的復(fù)合信息潭千,MyBatis 會(huì)根據(jù)列名從 ResultSet 中
         *      獲取列數(shù)據(jù)谱姓,并將列數(shù)據(jù)設(shè)置到實(shí)體類對(duì)象的指定屬性中,比如:
         *          Author{id=1, name="陳浩"}
         *      或是以鍵值對(duì) <屬性, 列數(shù)據(jù)> 的形式刨晴,將兩者存入 Map 中屉来。比如:
         *          {"id": 1, "name": "陳浩"}
         *
         *      至于參數(shù)類型到底為實(shí)體類還是 Map,取決于關(guān)聯(lián)查詢語(yǔ)句的配置信息割捅。比如:
         *          <select id="findAuthor">  ->  參數(shù)類型為 Map
         *          <select id="findAuthor" parameterType="Author"> -> 參數(shù)類型為實(shí)體類
         */
        final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
        Object value = null;
        if (nestedQueryParameterObject != null) {
            // 獲取 BoundSql奶躯,這里設(shè)置了運(yùn)行時(shí)參數(shù),所以這里是能直接執(zhí)行的
            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 {
                // 創(chuàng)建結(jié)果加載器
                final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
                // 檢測(cè)當(dāng)前屬性是否需要延遲加載
                if (propertyMapping.isLazy()) {
                    // 添加延遲加載相關(guān)的對(duì)象到 loaderMap 集合中
                    lazyLoader.addLoader(property, metaResultObject, resultLoader);
                    value = DEFERED;
                } else {
                    // 直接執(zhí)行關(guān)聯(lián)查詢
                    // 如果只是配置關(guān)聯(lián)查詢亿驾,但是沒(méi)有開啟懶加載嘹黔,則直接執(zhí)行關(guān)聯(lián)查詢,并返回結(jié)果,設(shè)置到實(shí)體類對(duì)象的屬性中
                    value = resultLoader.loadResult();
                }
            }
        }
        return value;
    }
}

下面先來(lái)總結(jié)一下該方法的邏輯:

  • 1儡蔓、根據(jù) nestedQueryId 獲取 MappedStatement
  • 2郭蕉、生成參數(shù)對(duì)象
  • 3、獲取 BoundSql
  • 4喂江、創(chuàng)建結(jié)果加載器 ResultLoader
  • 5召锈、檢測(cè)當(dāng)前屬性是否需要進(jìn)行延遲加載,若需要获询,則添加延遲加載相關(guān)的對(duì)象到loaderMap 集合中
  • 6涨岁、如不需要延遲加載,則直接通過(guò)結(jié)果加載器加載結(jié)果

以上流程中針對(duì)一級(jí)緩存的檢查是十分有必要的吉嚣,若緩存命中梢薪,可直接取用結(jié)果,無(wú)需再在執(zhí)行關(guān)聯(lián)查詢 SQL尝哆。若緩存未命中秉撇,接下來(lái)就要按部就班執(zhí)行延遲加載相關(guān)邏輯

我們來(lái)看一下添加延遲加載相關(guān)對(duì)象到 loaderMap 集合中的邏輯,如下:

public class ResultLoaderMap {

    private final Map<String, LoadPair> loaderMap = new HashMap<String, LoadPair>();

    public void addLoader(String property, MetaObject metaResultObject, ResultLoader resultLoader) {
        // 將屬性名轉(zhuǎn)為大寫
        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.");
        }
        // 創(chuàng)建 LoadPair秋泄,并將 <大寫屬性名琐馆,LoadPair對(duì)象> 鍵值對(duì)添加到 loaderMap 中
        loaderMap.put(upperFirst, new LoadPair(property, metaResultObject, resultLoader));
    }
}

我們?cè)賮?lái)回顧一下文章開始的創(chuàng)建實(shí)體類

public class DefaultResultSetHandler implements ResultSetHandler {

    private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
        this.useConstructorMappings = false; // reset previous mapping result
        final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
        final List<Object> constructorArgs = new ArrayList<Object>();
        
        // 調(diào)用重載方法創(chuàng)建實(shí)體類對(duì)象
        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) {
                // issue gcode #109 && issue #149
                // 如果開啟了延遲加載,則為 resultObject 生成代理類恒序,如果僅僅是配置的關(guān)聯(lián)查詢瘦麸,沒(méi)有開啟延遲加載,是不會(huì)創(chuàng)建代理類
                if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
                    /*
                     * 創(chuàng)建代理類奸焙,默認(rèn)使用 Javassist 框架生成代理類瞎暑。
                     * 由于實(shí)體類通常不會(huì)實(shí)現(xiàn)接口,所以不能使用 JDK 動(dòng)態(tài)代理 API 為實(shí)體類生成代理与帆。
                     * 并且將lazyLoader傳進(jìn)去了
                     */
                    resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
                    break;
                }
            }
        }
        this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
        return resultObject;
    }
}

如果開啟了延遲加載了赌,并且有關(guān)聯(lián)查詢,此時(shí)是要?jiǎng)?chuàng)建一個(gè)代理對(duì)象的玄糟,將上面存放BondSql的lazyLoader和創(chuàng)建的目標(biāo)對(duì)象resultObject 作為參數(shù)傳進(jìn)去勿她。

Mybatis提供了兩個(gè)實(shí)現(xiàn)類CglibProxyFactory和JavassistProxyFactory,分別基于org.javassist:javassist和cglib:cglib進(jìn)行實(shí)現(xiàn)阵翎。createProxy方法就是實(shí)現(xiàn)懶加載邏輯的核心方法逢并,也是我們分析的目標(biāo)。

CglibProxyFactory

CglibProxyFactory基于cglib動(dòng)態(tài)代理模式郭卫,通過(guò)繼承父類的方式生成動(dòng)態(tài)代理類砍聊。

public class CglibProxyFactory implements ProxyFactory {

    @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生成對(duì)象
        Object enhanced = crateProxy(type, callback, constructorArgTypes, constructorArgs);
        //復(fù)制屬性
        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);
        //設(shè)置父類對(duì)象
        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贰军,并調(diào)用構(gòu)造方法玻蝌,生成對(duì)象。從enhancer.setSuperclass(type);也能看出cglib采用的是繼承父類的方式。

EnhancedResultObjectProxyImpl

EnhancedResultObjectProxyImpl實(shí)現(xiàn)了MethodInterceptor接口俯树,此接口是Cglib攔截目標(biāo)對(duì)象方法的入口帘腹,對(duì)目標(biāo)對(duì)象方法的調(diào)用都會(huì)通過(guò)此接口的intercept的方法。

public class CglibProxyFactory implements ProxyFactory {

    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;

        @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许饿,或觸發(fā)方法(比如 equals阳欲,hashCode 等)被調(diào)用,
                             * 則加載所有的所有延遲加載的數(shù)據(jù)
                             */
                            if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
                                lazyLoader.loadAll();
                            } else if (PropertyNamer.isSetter(methodName)) {
                                // 如果使用者顯示調(diào)用了 setter 方法,則將相應(yīng)的延遲加載類從 loaderMap 中移除
                                final String property = PropertyNamer.methodToProperty(methodName);
                                lazyLoader.remove(property);
                             // 檢測(cè)使用者是否調(diào)用 getter 方法
                            } else if (PropertyNamer.isGetter(methodName)) {
                                final String property = PropertyNamer.methodToProperty(methodName);
                                if (lazyLoader.hasLoader(property)) {
                                    // 執(zhí)行延遲加載邏輯
                                    lazyLoader.load(property);
                                }
                            }
                        }
                    }
                }
                //執(zhí)行原方法(即父類方法)
                return methodProxy.invokeSuper(enhanced, args);
            } catch (Throwable t) {
                throw ExceptionUtil.unwrapThrowable(t);
            }
        }
    }
}

完整的代碼


// cglib代理工廠類,實(shí)現(xiàn)延遲加載屬性
public class CglibProxyFactory implements ProxyFactory {

  private static final Log log = LogFactory.getLog(CglibProxyFactory.class);
  //finalize方法
  private static final String FINALIZE_METHOD = "finalize";
  //writeReplace方法
  private static final String WRITE_REPLACE_METHOD = "writeReplace";

  //加載Enhancer,這個(gè)是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);
    }
  }

  /**
   * 創(chuàng)建代理對(duì)象
   * @param target 目標(biāo)對(duì)象
   * @param lazyLoader 延遲加載器
   * @param configuration 配置類
   * @param objectFactory 對(duì)象工廠
   * @param constructorArgTypes 構(gòu)造函數(shù)類型[]
   * @param constructorArgs  構(gòu)造函數(shù)的值[]
   * @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);
  }

  /**
   * 創(chuàng)建一個(gè)反序列化代理
   * @param target 目標(biāo)
   * @param unloadedProperties
   * @param objectFactory 對(duì)象工廠
   * @param constructorArgTypes 構(gòu)造函數(shù)類型數(shù)組
   * @param constructorArgs 構(gòu)造函數(shù)值
   * @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
  }

  /**
   * 返回代理對(duì)象, 這個(gè)代理對(duì)象在調(diào)用任何方法都會(huì)調(diào)用本類的intercept方法
   * Enhancer 認(rèn)為這個(gè)就是自定義類的工廠嘴纺,比如這個(gè)類需要實(shí)現(xiàn)什么接口
   * @param type 目標(biāo)類型
   * @param callback 結(jié)果對(duì)象代理實(shí)現(xiàn)類,當(dāng)中有invoke回調(diào)方法
   * @param constructorArgTypes 構(gòu)造函數(shù)類型數(shù)組
   * @param constructorArgs 構(gòu)造函數(shù)對(duì)應(yīng)字段的值數(shù)組
   * @return
   */
  static Object crateProxy(Class<?> type, Callback callback, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    // enhancer 配置調(diào)節(jié)代理對(duì)象的一些參數(shù)
    // 設(shè)置回調(diào)方法
    // 設(shè)置超類
    //判斷當(dāng)傳入目標(biāo)類型是否有writeReplace方法寥袭,沒(méi)有則配置一個(gè)有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 (log.isDebugEnabled()) {
        log.debug(WRITE_REPLACE_METHOD + " method was found on bean " + type + ", make sure it returns this");
      }
    } catch (NoSuchMethodException e) {
      //這個(gè)enhancer增加一個(gè)WriteReplaceInterface接口
      enhancer.setInterfaces(new Class[]{WriteReplaceInterface.class});
    } catch (SecurityException e) {
      // nothing to do here
    }
    
    //根據(jù)構(gòu)造函數(shù)創(chuàng)建一個(gè)對(duì)象
    //無(wú)參構(gòu)造
    //有參構(gòu)造  
    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;
  }

  /**
   * 結(jié)果對(duì)象代理實(shí)現(xiàn)類落恼,
   * 它實(shí)現(xiàn)方法攔截器的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;

    /**
     * 代理對(duì)象創(chuàng)建
     * @param type 目標(biāo)class類型
     * @param lazyLoader 延遲加載器
     * @param configuration 配置信息
     * @param objectFactory 對(duì)象工廠
     * @param constructorArgTypes 構(gòu)造函數(shù)類型數(shù)組
     * @param constructorArgs 構(gòu)造函數(shù)值數(shù)組
     */
    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;
    }

    /**
     * 創(chuàng)建代理對(duì)象, 將源對(duì)象值賦值給代理對(duì)象
     * @param target 目標(biāo)對(duì)象
     * @param lazyLoader 延遲加載器
     * @param configuration 配置對(duì)象
     * @param objectFactory 對(duì)象工廠
     * @param constructorArgTypes 構(gòu)造函數(shù)類型數(shù)組
     * @param constructorArgs 構(gòu)造函數(shù)值數(shù)組
     * @return
     */
    public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
      //獲取目標(biāo)的類型
      //創(chuàng)建一個(gè)結(jié)果對(duì)象代理實(shí)現(xiàn)類(它實(shí)現(xiàn)cglib的MethodInterface接口,完成回調(diào)作用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;
    }

    /**
     * 回調(diào)方法
     * @param enhanced 代理對(duì)象
     * @param method 方法
     * @param args 方法參數(shù)
     * @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 {
        // 同步獲取延遲加載對(duì)象
        // 如果是執(zhí)行writeReplace方法(序列化寫出)
        // 實(shí)例化一個(gè)目標(biāo)對(duì)象的實(shí)例   
        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中的屬性復(fù)制到orignal對(duì)象中
            // 如果延遲加載數(shù)量>0,          
            PropertyCopier.copyBeanProperties(type, enhanced, original);
            if (lazyLoader.size() > 0) {
              return new CglibSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
            } else {
              return original;
            }
          } else {
            //不是writeReplace方法
            // 延遲加載長(zhǎng)度大于0扯再, 且不是finalize方法
            // configuration配置延遲加載參數(shù)芍耘,延遲加載觸發(fā)的方法包含這個(gè)方法
            // 延遲加載所有數(shù)據(jù)       
            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);
      }
    }
  }

  /**
   * 他繼承抽象反序列化代理和實(shí)現(xiàn)了方法攔截
   */
  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);
    }

    /**
     * 創(chuàng)建代理對(duì)象
     * @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);
    }
  }
}

如上斋竞,代理方法首先會(huì)檢查 aggressive 是否為 true,如果不滿足秃殉,再去檢查 lazyLoadTriggerMethods 是否包含當(dāng)前方法名坝初。這里兩個(gè)條件只要一個(gè)為 true,當(dāng)前實(shí)體類中所有需要延遲加載钾军。aggressive 和 lazyLoadTriggerMethods 兩個(gè)變量的值取決于下面的配置鳄袍。

<setting name="aggressiveLazyLoading" value="false"/>
<setting name="lazyLoadTriggerMethods" value="equals,hashCode"/>

然后代理邏輯會(huì)檢查使用者是不是調(diào)用了實(shí)體類的 setter 方法,如果調(diào)用了吏恭,就將該屬性對(duì)應(yīng)的 LoadPair 從 loaderMap 中移除拗小。為什么要這么做呢?答案是:使用者既然手動(dòng)調(diào)用 setter 方法樱哼,說(shuō)明使用者想自定義某個(gè)屬性的值哀九。此時(shí),延遲加載邏輯不應(yīng)該再修改該屬性的值搅幅,所以這里從 loaderMap 中移除屬性對(duì)于的 LoadPair阅束。

最后如果使用者調(diào)用的是某個(gè)屬性的 getter 方法,且該屬性配置了延遲加載茄唐,此時(shí)延遲加載邏輯就會(huì)被觸發(fā)息裸。那接下來(lái),我們來(lái)看看延遲加載邏輯是怎樣實(shí)現(xiàn)的的。

public class ResultLoaderMap {

    private final Map<String, LoadPair> loaderMap = new HashMap<String, LoadPair>();
  
    public boolean load(String property) throws SQLException {
        // 從 loaderMap 中移除 property 所對(duì)應(yīng)的 LoadPair
        LoadPair pair = loaderMap.remove(property.toUpperCase(Locale.ENGLISH));
        if (pair != null) {
            // 加載結(jié)果
            pair.load();
            return true;
        }
        return false;
    }
    
    public void load() throws SQLException {
      /* These field should not be null unless the loadpair was serialized.
       * Yet in that case this method should not be called. */
      if (this.metaResultObject == null) {
        throw new IllegalArgumentException("metaResultObject is null");
      }
      if (this.resultLoader == null) {
        throw new IllegalArgumentException("resultLoader is null");
      }

      this.load(null);
    }
    
    public void load(final Object userObject) throws SQLException {
      if (this.metaResultObject == null || this.resultLoader == null) {
        if (this.mappedParameter == null) {
          throw new ExecutorException("Property [" + this.property + "] cannot be loaded because "
                  + "required parameter of mapped statement ["
                  + this.mappedStatement + "] is not serializable.");
        }

        final Configuration config = this.getConfiguration();
        final MappedStatement ms = config.getMappedStatement(this.mappedStatement);
        if (ms == null) {
          throw new ExecutorException("Cannot lazy load property [" + this.property
                  + "] of deserialized object [" + userObject.getClass()
                  + "] because configuration does not contain statement ["
                  + this.mappedStatement + "]");
        }

        this.metaResultObject = config.newMetaObject(userObject);
        this.resultLoader = new ResultLoader(config, new ClosedExecutor(), ms, this.mappedParameter,
                metaResultObject.getSetterType(this.property), null, null);
      }

      /* We are using a new executor because we may be (and likely are) on a new thread
       * and executors aren't thread safe. (Is this sufficient?)
       *
       * A better approach would be making executors thread safe. */
      if (this.serializationCheck == null) {
        final ResultLoader old = this.resultLoader;
        this.resultLoader = new ResultLoader(old.configuration, new ClosedExecutor(), old.mappedStatement,
                old.parameterObject, old.targetType, old.cacheKey, old.boundSql);
      }

    /*
     * 調(diào)用 ResultLoader 的 loadResult 方法加載結(jié)果界牡,
     * 并通過(guò) metaResultObject 設(shè)置結(jié)果到實(shí)體類對(duì)象中
     */
      this.metaResultObject.setValue(property, this.resultLoader.loadResult());
    }
}

public class ResultLoader {

    protected final ResultExtractor resultExtractor;

    protected Object resultObject;

    public Object loadResult() throws SQLException {
        // 執(zhí)行關(guān)聯(lián)查詢
        List<Object> list = selectList();
        // 抽取結(jié)果
        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 {
            // 通過(guò) Executor 就行查詢簿寂,這個(gè)之前已經(jīng)分析過(guò)了
            // 這里的parameterObject和boundSql就是我們之前存放在LoadPair中的,現(xiàn)在直接拿來(lái)執(zhí)行了
            return localExecutor.<E> query(mappedStatement, parameterObject, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, cacheKey, boundSql);
        } finally {
            if (localExecutor != executor) {
                localExecutor.close(false);
            }
        }
    }
}

好了宿亡,延遲加載我們基本已經(jīng)講清楚了常遂,我們介紹一下另外的一種代理方式

JavassistProxyFactory

JavassistProxyFactory使用的是javassist方式,直接修改class文件的字節(jié)碼格式挽荠。

/**JavassistProxy字節(jié)碼生成代理
 * 1.創(chuàng)建一個(gè)代理對(duì)象然后將目標(biāo)對(duì)象的值賦值給代理對(duì)象克胳,這個(gè)代理對(duì)象是可以實(shí)現(xiàn)其他的接口
 * 2. JavassistProxyFactory實(shí)現(xiàn)ProxyFactory接口createProxy(創(chuàng)建代理對(duì)象的方法)
 * @author Eduardo Macarron
 */
public class JavassistProxyFactory implements org.apache.ibatis.executor.loader.ProxyFactory {

  private static final Log log = LogFactory.getLog(JavassistProxyFactory.class);
  
  /**
   * 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);
    }
  }

  /**
   * 創(chuàng)建代理
   * @param target 目標(biāo)對(duì)象
   * @param lazyLoader 延遲加載Map集合(那些屬性是需要延遲加載的)
   * @param configuration 配置類
   * @param objectFactory 對(duì)象工廠
   * @param constructorArgTypes 構(gòu)造函數(shù)類型[]
   * @param constructorArgs  構(gòu)造函數(shù)的值[]
   * @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
  }

  /**
   * 獲取代理對(duì)象, 也就是說(shuō)在執(zhí)行方法之前首先調(diào)用MethodHanlder的invoke方法
   * @param type 目標(biāo)類型
   * @param callback 回調(diào)對(duì)象
   * @param constructorArgTypes 構(gòu)造函數(shù)類型數(shù)組
   * @param constructorArgs 構(gòu)造函數(shù)值的數(shù)組
   * @return
   */
  static Object crateProxy(Class<?> type, MethodHandler callback, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    // 創(chuàng)建一個(gè)代理工廠類
    // 配置超類
    ProxyFactory enhancer = new ProxyFactory();
    enhancer.setSuperclass(type);
    //判斷是否有writeReplace方法圈匆,如果沒(méi)有將這個(gè)代理對(duì)象實(shí)現(xiàn)WriteReplaceInterface接口漠另,這個(gè)接口只有一個(gè)writeReplace方法
    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;
    Class<?>[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
    Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);
    try {
      // 根據(jù)構(gòu)造函數(shù)創(chuàng)建一個(gè)代理對(duì)象
      enhanced = enhancer.create(typesArray, valuesArray);
    } catch (Exception e) {
      throw new ExecutorException("Error creating lazy proxy.  Cause: " + e, e);
    }
    // 設(shè)置回調(diào)對(duì)象
    ((Proxy) enhanced).setHandler(callback);
    return enhanced;
  }

  /**
   * 實(shí)現(xiàn)Javassist的MethodHandler接口, 相對(duì)于Cglib的MethodInterceptor
   * 他們接口的方法名也是不一樣的跃赚,Javassist的是invoke, 而cglib是intercept笆搓,叫法不同,實(shí)現(xiàn)功能是一樣的
   */
  private static class EnhancedResultObjectProxyImpl implements MethodHandler {
    /**
     * 目標(biāo)類型
     */
    private final Class<?> type;
    /**
     * 延遲加載Map集合
     */ 
    private final ResultLoaderMap lazyLoader;
    /**
     * 是否配置延遲加載
     */ 
    private final boolean aggressive;
    /**
     * 延遲加載觸發(fā)的方法
     */ 
    private final Set<String> lazyLoadTriggerMethods;
    /**
     * 對(duì)象工廠
     */ 
    private final ObjectFactory objectFactory;
    /**
     * 構(gòu)造函數(shù)類型數(shù)組
     */ 
    private final List<Class<?>> constructorArgTypes;
    /**
     * 構(gòu)造函數(shù)類型的值數(shù)組
     */ 
    private final List<Object> constructorArgs;

    /**
     * 構(gòu)造函數(shù)私有化了
     * @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) {
      // 獲取目標(biāo)類型
      // 創(chuàng)建一個(gè)EnhancedResultObjectProxyImpl對(duì)象纬傲,回調(diào)對(duì)象
      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;
    }

    /**
     * 回調(diào)方法
     * @param enhanced 代理對(duì)象
     * @param method 方法
     * @param methodProxy 代理方法
     * @param args 入?yún)?     * @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方法
            // 延遲加載長(zhǎng)度大于0满败, 且不是finalize方法
            // configuration配置延遲加載參數(shù),延遲加載觸發(fā)的方法包含這個(gè)方法
            // 延遲加載所有數(shù)據(jù)       
            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);
    }
  }
}

參考:
https://www.cnblogs.com/java-chen-hao/p/11760777.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末叹括,一起剝皮案震驚了整個(gè)濱河市算墨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌汁雷,老刑警劉巖净嘀,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異侠讯,居然都是意外死亡挖藏,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門继低,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)熬苍,“玉大人,你說(shuō)我怎么就攤上這事袁翁〔竦祝” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵粱胜,是天一觀的道長(zhǎng)柄驻。 經(jīng)常有香客問(wèn)我,道長(zhǎng)焙压,這世上最難降的妖魔是什么鸿脓? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任抑钟,我火速辦了婚禮,結(jié)果婚禮上野哭,老公的妹妹穿的比我還像新娘在塔。我一直安慰自己,他們只是感情好拨黔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布蛔溃。 她就那樣靜靜地躺著,像睡著了一般篱蝇。 火紅的嫁衣襯著肌膚如雪贺待。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天零截,我揣著相機(jī)與錄音麸塞,去河邊找鬼。 笑死涧衙,一個(gè)胖子當(dāng)著我的面吹牛哪工,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弧哎,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼正勒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了傻铣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤祥绞,失蹤者是張志新(化名)和其女友劉穎非洲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜕径,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡两踏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兜喻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梦染。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖朴皆,靈堂內(nèi)的尸體忽然破棺而出帕识,到底是詐尸還是另有隱情,我是刑警寧澤遂铡,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布肮疗,位于F島的核電站,受9級(jí)特大地震影響扒接,放射性物質(zhì)發(fā)生泄漏伪货。R本人自食惡果不足惜们衙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碱呼。 院中可真熱鬧蒙挑,春花似錦、人聲如沸愚臀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)懊悯。三九已至蜓谋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炭分,已是汗流浹背桃焕。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捧毛,地道東北人观堂。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像呀忧,于是被迫代替她去往敵國(guó)和親师痕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容