Mybatis-MapperAnnotationBuilder源码分析

Mybatis3.5.1源码分析

  1. Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
  2. Mybatis-Configuration源码解析
  3. Mybatis-事务对象源码解析
  4. Mybatis-数据源源码解析
  5. Mybatis缓存策略源码解析
  6. Mybatis-DatabaseIdProvider源码解析
  7. Mybatis-TypeHandler源码解析
  8. Mybatis-Reflector源码解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
  10. Mybatis-Mapper各类标签封装类源码解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
  12. Mybatis-MapperAnnotationBuilder源码分析
  13. [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源码解析
  15. Mybatis-SqlSource源码解析
  16. Mybatis-SqlNode源码解析
  17. Mybatis-KeyGenerator源码解析
  18. Mybatis-Executor源码解析
  19. Mybatis-ParameterHandler源码解析
  20. Mybatis-StatementHandler源码解析
  21. Mybatis-DefaultResultSetHandler(一)源码解析
  22. Mybatis-DefaultResultSetHandler(二)源码解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源码分析
  24. Mybatis-MapperProxy源码解析
  25. Mybatis-SqlSession源码解析
  26. Mybatis-Interceptor源码解析

MapperAnnotationBuilder

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.builder.annotation;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;

import org.apache.ibatis.annotations.Arg;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.CacheNamespaceRef;
import org.apache.ibatis.annotations.Case;
import org.apache.ibatis.annotations.ConstructorArgs;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Lang;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Options.FlushCachePolicy;
import org.apache.ibatis.annotations.Property;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.ResultType;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectKey;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.TypeDiscriminator;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.binding.BindingException;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.builder.CacheRefResolver;
import org.apache.ibatis.builder.IncompleteElementException;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Discriminator;
import org.apache.ibatis.mapping.FetchType;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultFlag;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.parsing.PropertyParser;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.UnknownTypeHandler;

/**
 * 映射器注解构建器
 * @author Clinton Begin
 * @author Kazuki Shimizu
 */
public class MapperAnnotationBuilder {

  /**
   * SQL脚本的注解类型
   * 

* 里面就是 {@link Select},{@link Insert},{@link Update},{@link Delete} *

*/ private static final Set> SQL_ANNOTATION_TYPES = new HashSet<>(); /** * SQL Provider 注解类型 *

* 里面就是 {@link SelectProvider},{@link UpdateProvider},{@link InsertProvider},{@link DeleteProvider} *

*

* SQL Provider注解用法:https://www.cnblogs.com/he-px/p/7134524.html *

*/ private static final Set> SQL_PROVIDER_ANNOTATION_TYPES = new HashSet<>(); /** * mybatis配置类 */ private final Configuration configuration; /** * 映射构建器助理 */ private final MapperBuilderAssistant assistant; /** * 当前接口类 */ private final Class type; static { SQL_ANNOTATION_TYPES.add(Select.class); SQL_ANNOTATION_TYPES.add(Insert.class); SQL_ANNOTATION_TYPES.add(Update.class); SQL_ANNOTATION_TYPES.add(Delete.class); SQL_PROVIDER_ANNOTATION_TYPES.add(SelectProvider.class); SQL_PROVIDER_ANNOTATION_TYPES.add(InsertProvider.class); SQL_PROVIDER_ANNOTATION_TYPES.add(UpdateProvider.class); SQL_PROVIDER_ANNOTATION_TYPES.add(DeleteProvider.class); } /** * * @param configuration Mybatis全局配置信息 * @param type 映射接口类 */ public MapperAnnotationBuilder(Configuration configuration, Class type) { //假设传进来的type.getName='bin.study.mapper.IUser',那么resource='bin/study/mapper/IUser.java (best guess)' String resource = type.getName().replace('.', '/') + ".java (best guess)"; //新建一个映射构建器助理 this.assistant = new MapperBuilderAssistant(configuration, resource); this.configuration = configuration; this.type = type; } /** * 解析映射接口类,解析mapper标签下的所有方法和注解,并对解析出来的信息加以封装, * 然后添加到Mybatis全局配置信息中。然后重新解析Mybatis全局配置信息中未能完成解析的 * Method重新解析 */ public void parse() { String resource = type.toString();//假设是 type='接口类IUser',resource就是'interface bin.study.mapper.IUser' //如果resource没有被加载过 if (!configuration.isResourceLoaded(resource)) { //加载对应接口的映射文件 loadXmlResource(); //将resource添加到已加载的资源集合中,以防止重新加载resource configuration.addLoadedResource(resource); //设置构建器助理的当前命名空间为type的包+类名 assistant.setCurrentNamespace(type.getName()); //解析CacheNamespace注解,构建一个Cache对象,并保存到Mybatis全局配置信息中 parseCache(); //解析CacheNamespace注解,引用CacheRef对应的Cache对象 parseCacheRef(); //获取结果中所有定义的方法 Method[] methods = type.getMethods(); for (Method method : methods) { try { // issue #237 如果method不是桥接方法,什么是桥接方法:https://www.cnblogs.com/zsg88/p/7588929.html if (!method.isBridge()) { //构建MapperStatement对象,并添加到Mybatis全局配置信息中 parseStatement(method); } } catch (IncompleteElementException e) { //当出现未完成元素时,添加构建Method时抛出异常的MethodResolver实例,到下个Mapper的解析时再次尝试解析 configuration.addIncompleteMethod(new MethodResolver(this, method)); } } } //解析未完成解析的Method parsePendingMethods(); } /** * 解析未完成解析的Method */ private void parsePendingMethods() { //获取未完成解析的Method集合 Collection incompleteMethods = configuration.getIncompleteMethods(); //同步加锁,防止多线程情况下,重复解析Method synchronized (incompleteMethods) { //获取未解析的Method集合迭代器 Iterator iter = incompleteMethods.iterator(); //遍历未解析的Method集合 while (iter.hasNext()) { try { //取出MethodResolver对象,重新解析,构建MapperStatement对象,并添加到Mybatis全局配置信息中 iter.next().resolve(); //移除解析成功的MethodResolver对象 iter.remove(); } catch (IncompleteElementException e) { // This method is still missing a resource //还是出现未完成解析异常的MethodResolver,留到再下一个Mapper重新解析 } } } } /** * 加载对应接口的映射文件 *

* 平时有些项目会将映射文件XML与接口类放在同一个包下,这个方法就是作用于这种方式去加载映射文件XML *

*/ private void loadXmlResource() { // Spring may not know the real resource name so we check a flag // to prevent loading again a resource twice // this flag is set at XMLMapperBuilder#bindMapperForNamespace /** * 因为Spring框架可能不知道真正的资源名,所以我们检查一个标记去防止加载两次资源。 * 这个标记设置在{@link XMLMapperBuilder#bindMapperForNamespace()} */ //判断是否加载过映射文件XML if (!configuration.isResourceLoaded("namespace:" + type.getName())) { //假设type='interface bin.study.mapper.IUser',那么xmlResource='bin/study/mapper/IUser.xml' String xmlResource = type.getName().replace('.', '/') + ".xml"; // #1347 //尝试加载映射文件 InputStream inputStream = type.getResourceAsStream("/" + xmlResource); //如果文件流为null if (inputStream == null) { // Search XML mapper that is not in the module but in the classpath. //搜索不在这模块里但是在这个类路径下的xml map try { inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource); } catch (IOException e2) { // ignore, resource is not required 忽略异常,因为这里的资源不是必须的 } } //如果文件流不null if (inputStream != null) { //新建一个XML映射构建器 XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName()); /** * 解析Mapper.xml,解析mapper标签下的所有标签,并对解析出来的标签信息加以封装, * 然后添加到Mybatis全局配置信息中。然后重新解析Mybatis全局配置信息中未能完成解析的 * ResultMap标签信息,CacheRef标签信息,DML标签信息 */ xmlParser.parse(); } } } /** * 解析CacheNamespace注解,构建一个Cache对象,并保存到Mybatis全局配置信息中 */ private void parseCache() { //CacheNamespace 相当于Mapper.xml的标签 CacheNamespace cacheDomain = type.getAnnotation(CacheNamespace.class); //如果有配置CacheNamespace注解 if (cacheDomain != null) { //获取最大缓存数 Integer size = cacheDomain.size() == 0 ? null : cacheDomain.size(); //获取刷新时间 Long flushInterval = cacheDomain.flushInterval() == 0 ? null : cacheDomain.flushInterval(); // 将 cacheDomain.properties() 转换成Properties Properties props = convertToProperties(cacheDomain.properties()); //构建一个Cache对象,并保存到Mybatis全局配置信息中 assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), flushInterval, size, cacheDomain.readWrite(), cacheDomain.blocking(), props); } } /** * 将 {@code properties} 转换成Properties * @param properties 属性数组 * @return Properties对象 */ private Properties convertToProperties(Property[] properties) { //如果属性数组为空 if (properties.length == 0) { //返回null return null; } //新建一个Properties对象,用于保存properties的元素 Properties props = new Properties(); //遍历properties for (Property property : properties) { /** * 先将property.value的有${...}形式的字符串转换成Mybatis全局配置信息维护变量表的对应字符串, * eg: '${first_name},${initial},${last_name}' => 'James,T,Kirk' * 再添加到props中 */ props.setProperty(property.name(), PropertyParser.parse(property.value(), configuration.getVariables())); } return props; } /** * 解析CacheNamespace注解,引用CacheRef对应的Cache对象 */ private void parseCacheRef() { //CacheNamespaceRef相当于Mapper.xml的CacheRef标签 CacheNamespaceRef cacheDomainRef = type.getAnnotation(CacheNamespaceRef.class); //如果有配置CacheNamespace注解 if (cacheDomainRef != null) { //获取Mapper接口类 Class refType = cacheDomainRef.value(); //获取Mapper.xml命名空间 String refName = cacheDomainRef.name(); //如果没有配置refType又没有配置refName if (refType == void.class && refName.isEmpty()) { //抛出异常 throw new BuilderException("Should be specified either value() or name() attribute in the @CacheNamespaceRef"); } //如果有配置refType又配置了refName if (refType != void.class && !refName.isEmpty()) { //抛出异常 throw new BuilderException("Cannot use both value() and name() attribute in the @CacheNamespaceRef"); } //如果配置了refType就用refType,否则使用refName String namespace = (refType != void.class) ? refType.getName() : refName; try { /** * CacheRef对应的Cache对象,会从Mybatis全局配信息中获取 {@code namespace} 对应的Cache对象, * 如果没有找到,会抛出IncompleteElementException异常,找到会将Cache对象赋值给 * currentCache,在构建MapperStatement对象时,将currentCache传进去 */ assistant.useCacheRef(namespace); //捕捉未完成元素构建成封装类异常 } catch (IncompleteElementException e) { //新建一个CacheRefResolver保存namespace和构建器助理对象,待解析构建下一个Mapper时再次尝试构建 configuration.addIncompleteCacheRef(new CacheRefResolver(assistant, namespace)); } } } /** * 构建ResultMap实例,包含discriminator的ResultMap实例,并添加到Mybatis全局配置信息, * 然后返回ResultMapId * @param method 方法对象 * @return ResultMapId */ private String parseResultMap(Method method) { //获取 method 的返回类型 Class returnType = getReturnType(method); //获取method配置的ConstructorArgs注解 ConstructorArgs args = method.getAnnotation(ConstructorArgs.class); //获取method配置的Results注解 Results results = method.getAnnotation(Results.class); //获取method配置的TypeDiscirminator注解 TypeDiscriminator typeDiscriminator = method.getAnnotation(TypeDiscriminator.class); /** * 生成method的resultMapId *
    *
  1. 如果有配置Results注解,拼装resultMapName=接口包名+类名+'.'+id属性值
  2. *
  3. 如果方法有参数 resultMapName=接口包名+类名+'.'+方法名+参数类型拼装字符串
  4. *
  5. 如果方法无参数resultMapName=接口包名+类名+'.'+方法名+'-void'
  6. *
*/ String resultMapId = generateResultMapName(method); //构建ResultMap实例,包含discriminator的ResultMap实例,并添加到Mybatis全局配置信息 applyResultMap(resultMapId, returnType, argsIf(args), resultsIf(results), typeDiscriminator); return resultMapId; } /** * 生成 {@code method} 的ResultMapName * @param method 方法对象 * @return *
    *
  1. 如果有配置Results注解,拼装resultMapName=接口包名+类名+'.'+id属性值
  2. *
  3. 如果方法有参数 resultMapName=接口包名+类名+'.'+方法名+参数类型拼装字符串
  4. *
  5. 如果方法无参数resultMapName=接口包名+类名+'.'+方法名+'-void'
  6. *
*/ private String generateResultMapName(Method method) { //获取method的Results注解 Results results = method.getAnnotation(Results.class); //如果有配置results注解 且 results注解id不为空 if (results != null && !results.id().isEmpty()) { //拼装resultMapName ,resultMapName=接口包名+类名+'.'+id属性值 return type.getName() + "." + results.id(); } //定义ResultMapName的后缀 StringBuilder suffix = new StringBuilder(); //遍历方法的参数类型数组 for (Class c : method.getParameterTypes()) { //添加'-'到suffix suffix.append("-"); //添加参数类型的类名到suffix suffix.append(c.getSimpleName()); } //如果suffix为空字符串 if (suffix.length() < 1) { //添加'-void'到suffix suffix.append("-void"); } //拼装resultMapName , // 如果方法有参数 resultMapName=接口包名+类名+'.'+方法名+参数类型拼装字符串 // 否则 resultMapName=接口包名+类名+'.'+方法名+'-void' return type.getName() + "." + method.getName() + suffix; } /** * 构建ResultMap实例,包含discriminator的ResultMap实例,并添加到Mybatis全局配置信息 * @param resultMapId resultMapId * @param returnType 返回类型 * @param args Arg注解集合,相当于arg标签,和idArg标签 * @param results result注解集合,相当于Result标签 * @param discriminator TypeDiscriminator注解,相当于discriminator标签 */ private void applyResultMap(String resultMapId, Class returnType, Arg[] args, Result[] results, TypeDiscriminator discriminator) { //定义一个ResultMapping类型集合,用于存放结果映射 List resultMappings = new ArrayList<>(); //应用构造函数参数,将 args 的每个元素封装成ResultMapping,添加到 resultMapping 中 applyConstructorArgs(args, returnType, resultMappings); //应用Result注解数组,将results的每个元素封装成ResultMapping,添加到resultMapping中 applyResults(results, returnType, resultMappings); //构建discriminator对象 Discriminator disc = applyDiscriminator(resultMapId, returnType, discriminator); // TODO add AutoMappingBehaviour //构建ResultMap实例,并添加到Mybatis全局配置信息 assistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null); //将鉴别器的Case配置信息封装成ResultMap,并添加到Mybatis全局配置信息 createDiscriminatorResultMaps(resultMapId, returnType, discriminator); } /** * 将鉴别器的Case配置信息封装成ResultMap,并添加到Mybatis全局配置信息 * @param resultMapId resultMapId * @param resultType 返回类型 * @param discriminator TypeDiscriminator注解 */ private void createDiscriminatorResultMaps(String resultMapId, Class resultType, TypeDiscriminator discriminator) { //如果方法有配置TypeDiscriminator注解 if (discriminator != null) { //遍历TypeDiscriminator注解的cases属性 for (Case c : discriminator.cases()) { //拼装caseResultMapId String caseResultMapId = resultMapId + "-" + c.value(); //定义一个ResultMapping类型集合,用于存放结果映射 List resultMappings = new ArrayList<>(); // issue #136 //应用构造函数参数,将 c.constructArgs() 的每个元素封装成ResultMapping,添加到 resultMapping 中 applyConstructorArgs(c.constructArgs(), resultType, resultMappings); //应用Result注解数组,将c.results()的每个元素封装成ResultMapping,添加到resultMapping中 applyResults(c.results(), resultType, resultMappings); // TODO add AutoMappingBehaviour //构建ResultMap实例,并添加到Mybatis全局配置信息 assistant.addResultMap(caseResultMapId, c.type(), resultMapId, null, resultMappings, null); } } } /** * 构建discriminator对象 * @param resultMapId resultMapId * @param resultType 返回类型 * @param discriminator TypeDiscriminator注解 * @return discriminator对象 */ private Discriminator applyDiscriminator(String resultMapId, Class resultType, TypeDiscriminator discriminator) { //如果方法有配置TypeDiscriminator注解 if (discriminator != null) { //获取TypeDiscriminator注解的列名 String column = discriminator.column(); //如果没有配置TypeDiscriminator注解的javaType,javaType就为String.class;否则javaType就是TypeDiscriminator注解的javaType Class javaType = discriminator.javaType() == void.class ? String.class : discriminator.javaType(); //如果没有配置TypeDiscriminator注解的jdbcType,jdbcType就为null;否则javaType就是TypeDiscriminator注解的jdbcType JdbcType jdbcType = discriminator.jdbcType() == JdbcType.UNDEFINED ? null : discriminator.jdbcType(); //如果discriminator的typeHandler属性值为UnknowTypeHandler,typeHandler就为null; // 否则typeHandler就是discriminator的typeHandler属性值 @SuppressWarnings("unchecked") Class> typeHandler = (Class>) (discriminator.typeHandler() == UnknownTypeHandler.class ? null : discriminator.typeHandler()); //获取TypeDiscriminator注解的Case注解数组 Case[] cases = discriminator.cases(); //定义鉴别器映射,用于存储Case注解的value,和resultMapId + "-" + value Map discriminatorMap = new HashMap<>(); //遍历Case注解数组 for (Case c : cases) { //获取Case注解的value属性值 String value = c.value(); //拼装caseResultMapId String caseResultMapId = resultMapId + "-" + value; //将Case注解的value属性值和caseResultMapId添加到discriminatorMap中 discriminatorMap.put(value, caseResultMapId); } //构建鉴别器对象 return assistant.buildDiscriminator(resultType, column, javaType, jdbcType, typeHandler, discriminatorMap); } return null; } /** * 构建MapperStatement对象,并添加到Mybatis全局配置信息中 * @param method 方法对象 */ void parseStatement(Method method) { /** * 获取参数类型,如果 {@code method} 的出现多个参数(不包含 RowBounds和ResultHandler)就返回ParamMap类型; * 如果只有一个参数(不包含 RowBounds和ResultHandler)就返回这一个参数类型 */ Class parameterTypeClass = getParameterType(method); /** * 获取语言驱动,由先获取{@code method}配置的Lang注解指定的驱动类,如果没有,使用默认的语言驱动类, * 默认的语言驱动为XMLLanguageDriver */ LanguageDriver languageDriver = getLanguageDriver(method); //从 method 的注解中构建SQL源对象 SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver); //如果SQL源对象不为null if (sqlSource != null) { //获取method中的Options注解对象 Options options = method.getAnnotation(Options.class); //拼装mappedStatementId final String mappedStatementId = type.getName() + "." + method.getName(); Integer fetchSize = null; Integer timeout = null; StatementType statementType = StatementType.PREPARED; ResultSetType resultSetType = null; //获取当前 method 的SqlCommandType枚举对象 SqlCommandType sqlCommandType = getSqlCommandType(method); //是否是查询指令 boolean isSelect = sqlCommandType == SqlCommandType.SELECT; //如果是查询指令,刷新缓存为false,否则为true boolean flushCache = !isSelect; //如果是查询指令,使用缓存为true;否则为false boolean useCache = isSelect; KeyGenerator keyGenerator; String keyProperty = null; String keyColumn = null; //如果sqlCommandType为插入指令类型 或者 sqlCommandType为修改指令类型 if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) { // first check for SelectKey annotation - that overrides everything else // 译文:先检查SelectKey注解,它将覆盖其他的一切 //获取method配置的SelectKey注解对象 SelectKey selectKey = method.getAnnotation(SelectKey.class); //如果selectKey不为null if (selectKey != null) { //构建 {@code selectKeyAnnotation} 对应的KeyGenerator对象, //并将KeyGenerator对象添加到Mybatis全局配置信息中 keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver); //获取seleckKey注解配置的填入将会被更新的参数对象的属性的值 keyProperty = selectKey.keyProperty(); //如果没有配置options注解 } else if (options == null) { //useGeneratedKeys:允许 JDBC 支持自动生成主键,需要驱动支持。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能支持但仍可正常工作(比如 Derby) //Jdbc3KeyGenerator:主要用于数据库的自增主键,比如 MySQL、PostgreSQL;会将执行SQL后从Statemenet中获取主键放到参数对象对应的属性里 //NoKeyGenerator: 什么事情都不干,里面是空实现方法 //如果isUseGeneratedKeys为true,就使用Jdbc3KeyGenerator;否则使用NoKeyGenerator keyGenerator = configuration.isUseGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; //如果selectKey为null 且 有配置options注解 } else { //如果options注解中的userGeneratedKey属性为true,就使用Jdbc3KeyGenerator; // 否则使用NoKeyGenerator keyGenerator = options.useGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; //获取options注解配置的填入将会被更新的参数对象的属性的值 keyProperty = options.keyProperty(); //获取options注解配置的匹配属性的返回结果集中的列名称 keyColumn = options.keyColumn(); } //如果sqlCommandType为select指令类型,或者delete指令类型 } else { //因为select和delete指令不会应该有KeyGenerator的功能,所以使用NoKeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; } //如果有配置options注解 if (options != null) { //FlushCachePolicy.TRUE 表示 不管是什么类型指令都刷新缓存 //如果options注解的flushCache为FlushCachePolicy.TRUE if (FlushCachePolicy.TRUE.equals(options.flushCache())) { //flushCach设置为true flushCache = true; //FlushCachePolicy.FALSE 表示 不管是什么类型指令都不刷新缓存 //如果options注解的flushCache为FlushCachePolicy.FALSE } else if (FlushCachePolicy.FALSE.equals(options.flushCache())) { //flushCach设置为false flushCache = false; } //options.useCache: 是否使用缓存,默认为true useCache = options.useCache(); //options.fetchSize:这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和 // 这个设置值相等。默认值为未设置(unset)(依赖驱动)。 // 先判断options.fetchSize取值范围是否大于-1,或者等于Integer.MIN_VALUE。 // 是就是引用options.fetchSize;否则为null fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348 //options.timeout:这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。 // 默认值为未设置(unset)(依赖驱动) // 先判断options.timeout的取值范围是否大于-1,是就应用options.timeout;否则为null timeout = options.timeout() > -1 ? options.timeout() : null; /** * SQL脚本类型,默认是 StatementType.PREPARED *
    *
  1. STATEMENT:对应于Statement对象,有SQL注入的风险
  2. *
  3. PREPARED:PreparedStatement,预编译处理
  4. *
  5. CALLABLE:CallableStatement一般调用存储过程的时候使用
  6. *
*/ statementType = options.statementType(); /** * ResultSet的常量,默认是DEFAULT *
    *
  1. DEFAULT:依赖驱动
  2. *
  3. FORWARD_ONLY:结果集的游标只能向下滚动
  4. *
  5. SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变
  6. *
  7. SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变
  8. *
*/ resultSetType = options.resultSetType(); } String resultMapId = null; //获取method的ResultMap注解 ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class); //如果有配置resultMap注解 if (resultMapAnnotation != null) { //拼装resultMap注解的配置的resultMapId,使用','进行拼接 resultMapId = String.join(",", resultMapAnnotation.value()); //如果是查询指令 } else if (isSelect) { //构建ResultMap实例,包含discriminator的ResultMap实例,并添加到Mybatis全局配置信息, //然后返回ResultMapId resultMapId = parseResultMap(method); } //构建MapperStatement对象,并添加到Mybatis全局配置信息中 assistant.addMappedStatement( mappedStatementId, sqlSource, statementType, sqlCommandType, fetchSize, timeout, // ParameterMapID null, parameterTypeClass, resultMapId, getReturnType(method), resultSetType, flushCache, useCache, // TODO gcode issue #577 false, keyGenerator, keyProperty, keyColumn, // DatabaseID null, languageDriver, // ResultSets options != null ? nullOrEmpty(options.resultSets()) : null); } } /** * 获取语言驱动,由先获取{@code method}配置的Lang注解指定的驱动类,如果没有,使用默认的语言驱动类, * 默认的语言驱动为XMLLanguageDriver * @param method 访对象 * @return {@code method}配置的Lang注解指定的驱动类,如果没有,使用默认的语言驱动类,默认的语言驱动为XMLLanguageDriver */ private LanguageDriver getLanguageDriver(Method method) { //获取method配置的Lang注解 Lang lang = method.getAnnotation(Lang.class); Class langClass = null; //如果method有加上Lang注解 if (lang != null) { //获取Lang注解配置的value赋值给langClass langClass = lang.value(); } //从Mybatis全局配置信息中获取语言驱动,当langClass为null时,会使用默认的语言驱动,默认的语言驱动为XMLLanguageDriver return configuration.getLanguageDriver(langClass); } /** * 获取参数类型,如果 {@code method} 的出现多个参数(不包含 RowBounds和ResultHandler)就返回ParamMap类型; * 如果只有一个参数(不包含 RowBounds和ResultHandler)就返回这一个参数类型 * @param method 方法对象 * @return 如果 {@code method} 的出现多个参数(不包含 RowBounds和ResultHandler)就返回ParamMap类型; * 如果只有一个参数(不包含 RowBounds和ResultHandler)就返回这一个参数类型 */ private Class getParameterType(Method method) { Class parameterType = null; //获取参数类型数组 Class[] parameterTypes = method.getParameterTypes(); //遍历参数类型 for (Class currentParameterType : parameterTypes) { //如果currentParameterType不是RowBound的子类或是本身,又不是ResultHandler的子类或者本身 if (!RowBounds.class.isAssignableFrom(currentParameterType) && !ResultHandler.class.isAssignableFrom(currentParameterType)) { //如果参数类型为null if (parameterType == null) { //将currentParameterType赋值给parameterType parameterType = currentParameterType; //参数类型不为null时,表示出现多个参数 } else { // issue #135 使用ParamMap作为参数类型 parameterType = ParamMap.class; } } } return parameterType; } /** * 获取 {@code method} 的返回类型 * @param method 方法对象 * @return {@code method} 的返回类型 */ private Class getReturnType(Method method) { //获取method的返回类型 Class returnType = method.getReturnType(); //解析获取method在type中的返回类型 Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, type); //如果reolvedReturnType是Class的子类 if (resolvedReturnType instanceof Class) { //强转resolvedReturnType为Class类型并赋值给returnType returnType = (Class) resolvedReturnType; //如果returnType是数组 if (returnType.isArray()) { //获取returnType的元素类型再次赋值给returnType returnType = returnType.getComponentType(); } // gcode issue #508 如果returnType为void类 if (void.class.equals(returnType)) { //获取method配置的ResultType注解 ResultType rt = method.getAnnotation(ResultType.class); //如果有配置resultType注解 if (rt != null) { //将resultType注解配置的结果对象类型赋值给returnType returnType = rt.value(); } } //ParameterizedType : 参数化类型,参考博客:https://blog.csdn.net/JustBeauty/article/details/81116144 //如果resolvedResturnType 是 ParameteizedType的子类 } else if (resolvedReturnType instanceof ParameterizedType) { //将resolvedReturnType强转成ParameterizedType类型,然后赋值给parameterizedType ParameterizedType parameterizedType = (ParameterizedType) resolvedReturnType; // 获取parameterizedType的原始类型并赋值给rawType Class rawType = (Class) parameterizedType.getRawType(); //如果rawType为Collection的子类或是其本身 有或者是Cursor的子类或是其本身 if (Collection.class.isAssignableFrom(rawType) || Cursor.class.isAssignableFrom(rawType)) { //获取parameterizedType的参数化类型参数数组 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); //如果actualTypeArguments不为null且actualTypeArguments只有一个元素 if (actualTypeArguments != null && actualTypeArguments.length == 1) { //获取actualTypeArguments的第一个元素并赋值给returnTypeParameter Type returnTypeParameter = actualTypeArguments[0]; //如果returnTypeParameter是Class类的子类或是其本身 if (returnTypeParameter instanceof Class) { //将returnTypeParameter强转为Class类型然后赋值给returnType returnType = (Class) returnTypeParameter; //如果returnTypeParameter是ParaeterizedType的子类或是其本身 } else if (returnTypeParameter instanceof ParameterizedType) { // (gcode issue #443) actual type can be a also a parameterized type //将returnTypeParameter强转为ParameterizedType类型赋值给returnType returnType = (Class) ((ParameterizedType) returnTypeParameter).getRawType(); //GenericArrayType是Type的子接口,用于表示“泛型数组”,描述的是形如:A[] // 或T[]的类型。其实也就是描述ParameterizedType类型以及TypeVariable类型的数组 // ,即形如:classA[][]、T[]等。 //如果returnTypeParameter是GenericArrayType的子类或是其本身 } else if (returnTypeParameter instanceof GenericArrayType) { //将returnTypeParameter强转为GenericArrayType类型赋值给componentType Class componentType = (Class) ((GenericArrayType) returnTypeParameter).getGenericComponentType(); // (gcode issue #525) support List // 新建一个长度为0的componentType类型数组对象并获取该数组对象的类赋值给returnType returnType = Array.newInstance(componentType, 0).getClass(); } } //如果method有配置MapKey注解 且 rawType是Map的子类或是其本身 } else if (method.isAnnotationPresent(MapKey.class) && Map.class.isAssignableFrom(rawType)) { // (gcode issue 504) Do not look into Maps if there is not MapKey annotation //获取parameterizedType的参数化类型参数数组 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); //如果actualTypeArguments不为null且actualTypeArguments只有两个元素 if (actualTypeArguments != null && actualTypeArguments.length == 2) { //获取Map的value类型 Type returnTypeParameter = actualTypeArguments[1]; //如果returnTypeParameter是Class的子类或是其本身 if (returnTypeParameter instanceof Class) { //将returnTypeParameter强转为Class类型赋值给returnType returnType = (Class) returnTypeParameter; //如果returnTypeParameter是ParameterizedType的子类或是其本身 } else if (returnTypeParameter instanceof ParameterizedType) { // (gcode issue 443) actual type can be a also a parameterized type //将returnTypeParameter强转为ParameterizedType类型赋值给returnType returnType = (Class) ((ParameterizedType) returnTypeParameter).getRawType(); } } //Optional:主要解决的问题是臭名昭著的空指针异常(NullPointerException) //如果rawType为Optional类 } else if (Optional.class.equals(rawType)) { //获取parameterizedType的参数化类型参数数组 Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); //获取参数化类型参数数组的第一个元素 Type returnTypeParameter = actualTypeArguments[0]; //如果returnTypeParameter是Class的子类或是其本身 if (returnTypeParameter instanceof Class) { //将returnTypeParameter强转为Class类型赋值给returnType returnType = (Class) returnTypeParameter; } } } return returnType; } /** * 从 {@code method} 的注解中构建SQL源对象 * @param method 方法对象 * @param parameterType 参数类型 * @param languageDriver 语言驱动 * @return ProviderSqlSource对象,ProviderSqlSource: SQL提供者的SQL源 */ private SqlSource getSqlSourceFromAnnotations(Method method, Class parameterType, LanguageDriver languageDriver) { try { //找出配置在method中的SQL指令类型注解,就是 {@link Select},{@link Insert},{@link Update},{@link Delete} Class sqlAnnotationType = getSqlAnnotationType(method); /** * 找出配置在 method中的SQL Provider 注解,就是 * {@link SelectProvider},{@link UpdateProvider},{@link InsertProvider},{@link DeleteProvider} */ Class sqlProviderAnnotationType = getSqlProviderAnnotationType(method); //如果有配置SQL指令类型 if (sqlAnnotationType != null) { //如果有配置SQL provide注解 if (sqlProviderAnnotationType != null) { //抛出异常,不可以同时配置SQL指令类型注解和SQL Provider 注解 throw new BindingException("You cannot supply both a static SQL and SqlProvider to method named " + method.getName()); } //获取sqlAnnotionType注解对象 Annotation sqlAnnotation = method.getAnnotation(sqlAnnotationType); //同过反射的方式取出SQL指令类型注解的value方法的返回值 final String[] strings = (String[]) sqlAnnotation.getClass().getMethod("value").invoke(sqlAnnotation); //将strings拼装成完整的SQL脚本字符串,然后通过languageDriver构建SQL源 return buildSqlSourceFromStrings(strings, parameterType, languageDriver); } else if (sqlProviderAnnotationType != null) { //获取sqlProviderAnnotationType注解对象 Annotation sqlProviderAnnotation = method.getAnnotation(sqlProviderAnnotationType); //新建一个SQL提供者的SQL源 return new ProviderSqlSource(assistant.getConfiguration(), sqlProviderAnnotation, type, method); } return null; } catch (Exception e) { throw new BuilderException("Could not find value method on SQL annotation. Cause: " + e, e); } } /** * 将 {@code strings} 拼装成完整的SQL脚本字符串,然后通过 {@code languageDriver} 构建SQL源 * @param strings sql脚本字符串数组 * @param parameterTypeClass 参数类型 * @param languageDriver 语言驱动 * @return SQL源 */ private SqlSource buildSqlSourceFromStrings(String[] strings, Class parameterTypeClass, LanguageDriver languageDriver) { //新建一个StringBuilder对象用于将strings转换成字符串 final StringBuilder sql = new StringBuilder(); //遍历strings for (String fragment : strings) { //添加fragemet到sql sql.append(fragment); //添加空格到sql sql.append(" "); } //通过语音驱动构建SQL源 return languageDriver.createSqlSource(configuration, sql.toString().trim(), parameterTypeClass); } /** * 获取 {@code method} 的SqlCommandType枚举对象 * @param method 方法对象 * @return {@code method} 的SQL指令类型 */ private SqlCommandType getSqlCommandType(Method method) { /** * 找出配置在 {@code method} 中的SQL指令类型注解, * 就是 {@link Select},{@link Insert},{@link Update},{@link Delete} */ Class type = getSqlAnnotationType(method); //如果没有配置SQL指令类型 if (type == null) { /** * 找出配置在 {@code method} 中的SQL Provider 注解类型,就是 * {@link SelectProvider},{@link UpdateProvider},{@link InsertProvider},{@link DeleteProvider} */ type = getSqlProviderAnnotationType(method); //如果没有配置SQL provider注解类型 if (type == null) { //直接返回 未知的SQL指令类型 return SqlCommandType.UNKNOWN; } //如果类型等于SelectProvider注解 if (type == SelectProvider.class) { //类型就是为Select注解 type = Select.class; //如果类型等于InsertProvider注解 } else if (type == InsertProvider.class) { //类型就是为Insert注解 type = Insert.class; //如果类型等于UpdateProvider注解 } else if (type == UpdateProvider.class) { //类型就是Update注解 type = Update.class; //如果类型等于DeleteProvider注解 } else if (type == DeleteProvider.class) { //类型就是Delete注解 type = Delete.class; } } //对应type对应的SqlCommandType枚举对象 return SqlCommandType.valueOf(type.getSimpleName().toUpperCase(Locale.ENGLISH)); } /** * 找出配置在 {@code method} 中的SQL指令类型,就是 {@link Select},{@link Insert},{@link Update},{@link Delete} * @param method 方法对象 * @return SQL指令类型,就是 {@link Select},{@link Insert},{@link Update},{@link Delete} */ private Class getSqlAnnotationType(Method method) { //找出 method 中第一个对应 SQL_ANNOTATION_TYPES 的元素的注解 return chooseAnnotationType(method, SQL_ANNOTATION_TYPES); } /** * 找出配置在 {@code method} 中的SQL Provider 注解类型,就是 * {@link SelectProvider},{@link UpdateProvider},{@link InsertProvider},{@link DeleteProvider} * @param method 方法对象 * @return SQL Provider 注解类型,就是 * {@link SelectProvider},{@link UpdateProvider},{@link InsertProvider},{@link DeleteProvider} */ private Class getSqlProviderAnnotationType(Method method) { ////找出 method 中第一个对应 SQL_PROVIDER_ANNOTATION_TYPES 的元素的注解 return chooseAnnotationType(method, SQL_PROVIDER_ANNOTATION_TYPES); } /** * 找出 {@code method} 中第一个对应 {@code types}的元素的注解 * @param method 方法对象 * @param types 注解集合 * @return {@code method} 中第一个对应 {@code types}的元素的注解 */ private Class chooseAnnotationType(Method method, Set> types) { //遍历注解列表 for (Class type : types) { //从method中获取type注解对象 Annotation annotation = method.getAnnotation(type); //如果method中有配置type注解 if (annotation != null) { //直接返回注解 return type; } } return null; } /** * 应用Result注解数组,将 {@code results} 的每个元素封装成ResultMapping,添加到 {@code resultMapping}中 * @param results Result注解数组 * @param resultType 返回类型 * @param resultMappings 结果映射集合 */ private void applyResults(Result[] results, Class resultType, List resultMappings) { //遍历Result注解数组 for (Result result : results) { //ResultFlag枚举类型:ResultFlag.ID-表示是个表主键;ResultFlag.CONSTRUCTOR-表示是个构造函数参数 //定义存放ResultFlag的集合 List flags = new ArrayList<>(); //如果result的id属性为true if (result.id()) { //添加主键标记给flags flags.add(ResultFlag.ID); } //如果result的typeHandler属性值为UnknowTypeHandler,typeHandler就为null; // 否则typeHandler就是result的typeHandler属性值 @SuppressWarnings("unchecked") Class> typeHandler = (Class>) ((result.typeHandler() == UnknownTypeHandler.class) ? null : result.typeHandler()); //对Result注解配置信息封装ResultMapping对象 ResultMapping resultMapping = assistant.buildResultMapping( resultType, nullOrEmpty(result.property()), nullOrEmpty(result.column()), result.javaType() == void.class ? null : result.javaType(), result.jdbcType() == JdbcType.UNDEFINED ? null : result.jdbcType(), hasNestedSelect(result) ? nestedSelectId(result) : null, null, null, null, typeHandler, flags, null, null, isLazy(result)); //将resultMapping添加到resultMapping集合中 resultMappings.add(resultMapping); } } private String nestedSelectId(Result result) { String nestedSelect = result.one().select(); if (nestedSelect.length() < 1) { nestedSelect = result.many().select(); } if (!nestedSelect.contains(".")) { nestedSelect = type.getName() + "." + nestedSelect; } return nestedSelect; } private boolean isLazy(Result result) { boolean isLazy = configuration.isLazyLoadingEnabled(); if (result.one().select().length() > 0 && FetchType.DEFAULT != result.one().fetchType()) { isLazy = result.one().fetchType() == FetchType.LAZY; } else if (result.many().select().length() > 0 && FetchType.DEFAULT != result.many().fetchType()) { isLazy = result.many().fetchType() == FetchType.LAZY; } return isLazy; } private boolean hasNestedSelect(Result result) { if (result.one().select().length() > 0 && result.many().select().length() > 0) { throw new BuilderException("Cannot use both @One and @Many annotations in the same @Result"); } return result.one().select().length() > 0 || result.many().select().length() > 0; } /** * 应用构造函数参数,将 {@code args} 的每个元素封装成ResultMapping,添加到 {@code resultMapping}中 * @param args Arg注解数组 * @param resultType 返回类型 * @param resultMappings 结果映射集合 */ private void applyConstructorArgs(Arg[] args, Class resultType, List resultMappings) { //遍历Arg注解数组 for (Arg arg : args) { //ResultFlag枚举类型:ResultFlag.ID-表示是个表主键;ResultFlag.CONSTRUCTOR-表示是个构造函数参数 //定义存放ResultFlag的集合 List flags = new ArrayList<>(); //添加构建函数标记给flags flags.add(ResultFlag.CONSTRUCTOR); //如果arg的id属性为true if (arg.id()) { //添加主键标记给flags flags.add(ResultFlag.ID); } //如果arg的typeHandler属性值为UnknowTypeHandler,typeHandler就为null; // 否则typeHandler就是arg的typeHandler属性值 @SuppressWarnings("unchecked") Class> typeHandler = (Class>) (arg.typeHandler() == UnknownTypeHandler.class ? null : arg.typeHandler()); //arg注解配置信息封装ResultMapping对象 ResultMapping resultMapping = assistant.buildResultMapping( resultType, nullOrEmpty(arg.name()), nullOrEmpty(arg.column()), arg.javaType() == void.class ? null : arg.javaType(), arg.jdbcType() == JdbcType.UNDEFINED ? null : arg.jdbcType(), nullOrEmpty(arg.select()), nullOrEmpty(arg.resultMap()), null, nullOrEmpty(arg.columnPrefix()), typeHandler, flags, null, null, false); //将resultMapping添加到resultMapping集合中 resultMappings.add(resultMapping); } } /** * 如果 {@code value} 为null或者为空字符串,都会返回null;否则返回 {@code value} * @param value 值 */ private String nullOrEmpty(String value) { return value == null || value.trim().length() == 0 ? null : value; } private Result[] resultsIf(Results results) { return results == null ? new Result[0] : results.value(); } private Arg[] argsIf(ConstructorArgs args) { return args == null ? new Arg[0] : args.value(); } /** * 构建 {@code selectKeyAnnotation} 对应的KeyGenerator对象,并将KeyGenerator对象添加到 * Mybatis全局配置信息中 * @param selectKeyAnnotation SelectKey注解对象 * @param baseStatementId MappedStatement对象Id * @param parameterTypeClass 参数类型 * @param languageDriver 语言驱动 * @return {@code selectKeyAnnotation} 对应的KeyGenerator对象 */ private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, String baseStatementId, Class parameterTypeClass, LanguageDriver languageDriver) { //拼装SelectKeyId,SelectKeyId=MappedStatement对象Id+'!selectKey' String id = baseStatementId + SelectKeyGenerator.SELECT_KEY_SUFFIX; //获取selectKey注解配置的keyPropety属性的java类型 Class resultTypeClass = selectKeyAnnotation.resultType(); //获取selectKey注解配置的SQL脚本类型 StatementType statementType = selectKeyAnnotation.statementType(); //获取seleckKey注解配置的填入将会被更新的参数对象的属性的值 String keyProperty = selectKeyAnnotation.keyProperty(); //获取selectKey注解配置的 匹配属性的返回结果集中的列名称 String keyColumn = selectKeyAnnotation.keyColumn(); //获取selectKey注解配置的 SQL 语句应被在插入语句的之前还是之后执行标记 boolean executeBefore = selectKeyAnnotation.before(); // defaults 定义默认值 //定义不使用缓存 boolean useCache = false; //定义KeyGenerator为NoKeyGenerator.NoKeyGenerator:什么事情都不干,里面是空实现方法 KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; //fetchSize:这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动) Integer fetchSize = null; //timeout:这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。 Integer timeout = null; //flushCache:将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 boolean flushCache = false; //参数映射 String parameterMap = null; //结果映射 String resultMap = null; /** * FORWARD_ONLY:结果集的游标只能向下滚动, * SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变, * SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变 * DEFAULT:依赖驱动(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。 */ ResultSetType resultSetTypeEnum = null; /** * 将 selectKey注解的会被执行的 SQL 字符串数组 拼装成完整的SQL脚本字符串, * 然后通过languageDriver 构建SQL源 */ SqlSource sqlSource = buildSqlSourceFromStrings(selectKeyAnnotation.statement(), parameterTypeClass, languageDriver); //设置sql指令类型为SELECT SqlCommandType sqlCommandType = SqlCommandType.SELECT; //构建MapperStatement对象,并添加到全局配置信息中 assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, false, keyGenerator, keyProperty, keyColumn, null, languageDriver, null); //检查ID是否简写,简写就应用当前命名空间+id id = assistant.applyCurrentNamespace(id, false); // 根据id 获取对应的MappedStatement对象 MappedStatement keyStatement = configuration.getMappedStatement(id, false); // 用于执行selectKey标签的SQL,将结果赋值到参数对象对应的属性中 SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, executeBefore); //添加 KeyGenerator对象到Mybatis全局配置信息 configuration.addKeyGenerator(id, answer); return answer; } }

你可能感兴趣的:(Mybatis-MapperAnnotationBuilder源码分析)