Mybatis在一个方法执行的时候实际上是进入了MapperProxy的invoke方法,如果是查询,一路下去,后面进入了RoutingStatementHandler的query()方法。
一、NativeMethodAccessorImpl
在后面会发现调用method.invoke()方法的时候,都进入了NativeMethodAccessorImpl方法中,这个类中有个native,很多人看源码的时候,觉得源码到这个地方就结束了,native方法是去调用本地方法了,后面就查看不了了。其实NativeMethodAccessorImpl.invoke0()是java发射类的一个方法,后面调用的还是你的java代码,其原理如下:JAVA深入研究——Method的Invoke方法,关于asm反射性能:ASM 高性能的反射。
二、返回类型的确定
在mybatis plus中都是一水的实体类返回,没看到返回单个字段的,这是为什么呢,在填充返回类型的时候mybatis plus用到了一个类BaseTypeHandler,这个类是在填充返回参数的时候使用的,其子类有LongTypeHandler,IntegerTyperHandler等多种,关于是那种类型的TypeHandler,是从DefaultResultSetHandler中获取的:
@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);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
其中的resultMaps是从mappedStatement中获取到的。它的初始化是在服务启动的时候,MapperBuilderAssistant中:
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
MappedStatement statement = statementBuilder.build();
configuration.addMappedStatement(statement);
return statement;
}
三、17种sql
在mybatis plus中默认的sql有17种,如下
如果以SelectMaps为例:
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
SqlMethod sqlMethod = SqlMethod.SELECT_MAPS;
String sql = String.format(sqlMethod.getSql(), sqlSelectColumns(tableInfo, true),
tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo));
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, Map.class, tableInfo);
}
其返回类型都已经定义好了,
如果要自己定义返回类型,就要自己去写自己定义的类。
四、Inteceptor
- 在Mybatis中还有拦截器Inteceptor类,关于Inteceptor的源码分析,可以参考文章:《利用职责链和代理模式实现Mybatis Plugin》
- 《BaseExecutor使用的模板模式》