MetaObject用於反射建立對象、反射從對象中獲取屬性值、反射給對象設置屬性值,參數設置和結果封裝,用的都是這個MetaObject提供的功能。緩存
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { if (object == null) { return SystemMetaObject.NULL_META_OBJECT; } else { return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory); } }
public Object getValue(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return null; } else { return metaValue.getValue(prop.getChildren()); } } else { return objectWrapper.get(prop); } } public void setValue(String name, Object value) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { if (value == null && prop.getChildren() != null) { // don't instantiate child path if value is null return; } else { metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } } metaValue.setValue(prop.getChildren(), value); } else { objectWrapper.set(prop, value); } }
Object object:要反射的對象,好比Student。app
ObjectFactory objectFactory:經過Class對象反射建立對象實例的工廠類,好比建立一個User對象。ide
ObjectWrapperFactory :對目標對象進行包裝,好比能夠將Properties對象包裝成爲一個Map並返回Map對象。函數
ReflectorFactory :爲了不屢次反射同一個Class對象,ReflectorFactory提供了Class對象的反射結果緩存。this
getValue(String name):屬性取值。spa
setValue(String name, Object value):屬性賦值。code
Mybatis的結果封裝,分爲兩種,一種是有ResultMap映射表,明肯定義告終果集列名與對象屬性名的配對關係,另一種是對象類型,沒有明肯定義結果集列名與對象屬性名的配對關係,如resultType是User對象。對象
<resultMap type="userT" id="userResult"> <id property="id" column="t_id"/> <result property="name" column="name" /> </resultMap> <select id="findUserById" resultMap="userResult"> select * from m_user where id = #{id} </select>
原理很是簡單:使用ObjectFactory ,建立一個userT對象實例。繼承
userT.setId(resultSet.getInt("t_id"));接口
userT.setName(resultSet.getString("name"));
若是是對象類型,如User對象相似,原理也很是簡單。
<select id="findUserById" resultType="com.lpf.entity.User"> select * from m_user where id = #{id} </select>
原理:使用ObjectFactory ,建立一個User對象實例。
user.setId(resultSet.getInt("id"));
user.setName(resultSet.getString("name"));
DefaultResultSetHandler繼承了,ResultSetHandler是一個接口,提供了兩個函數分別用來處理普通操做和存儲過程的結果,
源碼以下:
/** * @author Clinton Begin */ public interface ResultSetHandler { <E> List<E> handleResultSets(Statement stmt) throws SQLException; <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException; void handleOutputParameters(CallableStatement cs) throws SQLException; }
DefaultResultSetHandler,其實現的步驟就是將Statement執行後的結果集,按照Mapper文件中配置的ResultType或ResultMap來封裝成對應的對象,最後將封裝的對象返回便可,
結果封裝實現原理
DefaultResultSetHandler部分源碼以下:
public class DefaultResultSetHandler implements ResultSetHandler { private static final Object DEFERED = new Object(); // 此Map用來保存當前層級內部的結果對象(一對多關係的多方對象),key爲combinedKey private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>(); // 此Map用來保存當前層級的根對象(一對多關係中的一方對象),key爲absoluteKey private final Map<String, Object> ancestorObjects = new HashMap<String, Object>(); private Object previousRowValue; // multiple resultsets private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>(); private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>(); // Cached Automappings private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<String, List<UnMappedColumnAutoMapping>>(); // temporary marking flag that indicate using constructor mapping (use field to reduce memory usage) private boolean useConstructorMappings; private final PrimitiveTypes primitiveTypes; private static class PendingRelation { public MetaObject metaObject; public ResultMapping propertyMapping; } /** * 調用存儲過程返回結果,將結果值放在參數中 * @param cs * @throws SQLException */ @Override public void handleOutputParameters(CallableStatement cs) throws SQLException { final Object parameterObject = parameterHandler.getParameterObject(); final MetaObject metaParam = configuration.newMetaObject(parameterObject); final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); for (int i = 0; i < parameterMappings.size(); i++) { final ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) { if (ResultSet.class.equals(parameterMapping.getJavaType())) { handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam); } else { final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler(); metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1)); } } } } /** * 對普通查詢到的結果轉換 * @param stmt * @return * @throws SQLException */ @Override 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; //獲取第一個結果值 ResultSetWrapper rsw = getFirstResultSet(stmt); //得到resultMap List<ResultMap> resultMaps = mappedStatement.getResultMaps(); //這邊應該爲1吧,通常resultMap爲一個 int resultMapCount = resultMaps.size(); //判斷是否有resultMap,沒有的話拋出異常 validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { //得到resultMap,實體類和表中數據字段的對應關係 ResultMap resultMap = resultMaps.get(resultSetCount); //將值設置成對應的resultmap對象 handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } //得到resultSets String[] resultSets = mappedStatement.getResultSets(); if (resultSets != null) { 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); } //得到第一個值,並將值打包 private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException { ResultSet rs = stmt.getResultSet(); while (rs == null) { // move forward to get the first resultset in case the driver // doesn't return the resultset as the first result (HSQLDB 2.1) if (stmt.getMoreResults()) { rs = stmt.getResultSet(); } else { if (stmt.getUpdateCount() == -1) { // no more results. Must be no resultset break; } } } return rs != null ? new ResultSetWrapper(rs, configuration) : null; } //獲取下一個值,將值打包 private ResultSetWrapper getNextResultSet(Statement stmt) throws SQLException { // Making this method tolerant of bad JDBC drivers try { if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) { // Crazy Standard JDBC way of determining if there are more results if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) { ResultSet rs = stmt.getResultSet(); if (rs == null) { return getNextResultSet(stmt); } else { return new ResultSetWrapper(rs, configuration); } } } } catch (Exception e) { // Intentionally ignored. } return null; } //關閉resultSet private void closeResultSet(ResultSet rs) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { // ignore } } //校驗結果的resultMap,若是沒有的話就拋出異常 private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) { if (rsw != null && resultMapCount < 1) { throw new ExecutorException("A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId() + "'. It's likely that neither a Result Type nor a Result Map was specified."); } } 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); //將查詢到的每一個字段和Bean實體中的屬性對應起來,生成一個Result對象 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); //結果映射對象及值添加到multipleResults中 multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) closeResultSet(rsw.getResultSet()); } } //操做列值 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); } } //判斷記錄行數 private void ensureNoRowBounds() { if (configuration.isSafeRowBoundsEnabled() && rowBounds != null && (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) { throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. " + "Use safeRowBoundsEnabled=false setting to bypass this check."); } } private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>(); skipRows(rsw.getResultSet(), rowBounds); while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null); Object rowValue = getRowValue(rsw, discriminatedResultMap); storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); } } private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException { final ResultLoaderMap lazyLoader = new ResultLoaderMap(); 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)) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; foundValues = lazyLoader.size() > 0 || foundValues; rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null; } return rowValue; } private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { if (propertyMapping.getNestedQueryId() != null) {//關聯查詢 // 執行另一個select查詢,把查詢結果賦值給屬性值,好比Student對象的teacher屬性 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); return typeHandler.getResult(rs, column); } } //建立結果對象 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>(); //結果對象 Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix); if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { //獲取配置的resultMap的字段與表中數據的映射關係 final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings(); for (ResultMapping propertyMapping : propertyMappings) { // issue gcode #109 && issue #149 if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) { resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs); break; } } } this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result return resultObject; } //獲得嵌套查詢值 private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { final String nestedQueryId = propertyMapping.getNestedQueryId(); final String property = propertyMapping.getProperty(); final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId); final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType(); final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix); Object value = null; if (nestedQueryParameterObject != null) { 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)) { //若是已經有一級緩存了,則延遲加載(實際上deferLoad方法中能夠看到則是當即加載) executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType); value = DEFERED; } else { // ResultLoader保存了關聯查詢所須要的全部信息 final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql); if (propertyMapping.isLazy()) { // 執行延遲加載 // 語意:resultLoader的查詢結果將賦值給metaResultObject源對象的property屬性,resultLoader的查詢參數值來自於metaResultObject源對象屬性中。 // 舉例:查詢Teacher,賦值給Student的teacher屬性,參數來自於查詢Student的ResultSet的teacher_id列的值。 // 因爲須要執行延遲加載,將查詢相關信息放入緩存,但不執行查詢,使用該屬性時,自動觸發加載操做。 lazyLoader.addLoader(property, metaResultObject, resultLoader); value = DEFERED; } else { // 不執行延遲加載,當即查詢並賦值 value = resultLoader.loadResult(); } } } return value; } //生成嵌套對象值 一對多查詢 private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { final DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>(); skipRows(rsw.getResultSet(), rowBounds); Object rowValue = previousRowValue; // 解決鑑別過的結果映射,邏輯以下: // 獲取結果映射中的鑑別器,經過鑑別指定字段經過配置對象獲取對應的另外一個結果映射,循環往復, // 直到找不到鑑別器爲止,返回最終的結果映射 while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null); final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null); Object partialObject = nestedResultObjects.get(rowKey); // issue #577 && #542 if (mappedStatement.isResultOrdered()) { if (partialObject == null && rowValue != null) { nestedResultObjects.clear(); storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); } rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject); } else { rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject); if (partialObject == null) { storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); } } } if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) { storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); previousRowValue = null; } else if (rowValue != null) { previousRowValue = rowValue; } } private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException { final String resultMapId = resultMap.getId(); Object rowValue = partialObject; if (rowValue != null) { final MetaObject metaObject = configuration.newMetaObject(rowValue); putAncestor(rowValue, resultMapId); applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false); ancestorObjects.remove(resultMapId); } else { final ResultLoaderMap lazyLoader = new ResultLoaderMap(); rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix); if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { final MetaObject metaObject = configuration.newMetaObject(rowValue); boolean foundValues = this.useConstructorMappings; if (shouldApplyAutomaticMappings(resultMap, true)) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues; putAncestor(rowValue, resultMapId); // 解析NestedResultMappings並封裝結果,賦值給源對象的關聯查詢屬性上 foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues; ancestorObjects.remove(resultMapId); foundValues = lazyLoader.size() > 0 || foundValues; rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null; } if (combinedKey != CacheKey.NULL_CACHE_KEY) { nestedResultObjects.put(combinedKey, rowValue); } } return rowValue; } private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) { boolean foundValues = false; for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) { final String nestedResultMapId = resultMapping.getNestedResultMapId(); if (nestedResultMapId != null && resultMapping.getResultSet() == null) { try { final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping); final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix); if (resultMapping.getColumnPrefix() == null) { // try to fill circular reference only when columnPrefix // is not specified for the nested result map (issue #215) Object ancestorObject = ancestorObjects.get(nestedResultMapId); if (ancestorObject != null) { if (newObject) { linkObjects(metaObject, resultMapping, ancestorObject); // issue #385 } continue; } } final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix); final CacheKey combinedKey = combineKeys(rowKey, parentRowKey); Object rowValue = nestedResultObjects.get(combinedKey); boolean knownValue = rowValue != null; instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) { rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue); if (rowValue != null && !knownValue) { linkObjects(metaObject, resultMapping, rowValue); foundValues = true; } } } catch (SQLException e) { throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'. Cause: " + e, e); } } } return foundValues; } }