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源码解析]//www.greatytc.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脚本的注解类型
   * <p>
   *     里面就是 {@link Select},{@link Insert},{@link Update},{@link Delete}
   * </p>
   */
  private static final Set<Class<? extends Annotation>> SQL_ANNOTATION_TYPES = new HashSet<>();
  /**
   * SQL Provider 注解类型
   * <p>
   *     里面就是 {@link SelectProvider},{@link UpdateProvider},{@link InsertProvider},{@link DeleteProvider}
   * </p>
   * <p>
   *     SQL Provider注解用法:<a href='https://www.cnblogs.com/he-px/p/7134524.html'>https://www.cnblogs.com/he-px/p/7134524.html</a>
   * </p>
   */
  private static final Set<Class<? extends Annotation>> 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<MethodResolver> incompleteMethods = configuration.getIncompleteMethods();
    //同步加锁,防止多线程情况下,重复解析Method
    synchronized (incompleteMethods) {
      //获取未解析的Method集合迭代器
      Iterator<MethodResolver> 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重新解析
        }
      }
    }
  }

  /**
   * 加载对应接口的映射文件
   * <p>
   *     平时有些项目会将映射文件XML与接口类放在同一个包下,这个方法就是作用于这种方式去加载映射文件XML
   * </p>
   */
  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的<cache>标签
    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
     * <ol>
     *     <li>如果有配置Results注解,拼装resultMapName=接口包名+类名+'.'+id属性值</li>
     *     <li>如果方法有参数 resultMapName=接口包名+类名+'.'+方法名+参数类型拼装字符串</li>
     *     <li>如果方法无参数resultMapName=接口包名+类名+'.'+方法名+'-void'</li>
     * </ol>
     */
    String resultMapId = generateResultMapName(method);
    //构建ResultMap实例,包含discriminator的ResultMap实例,并添加到Mybatis全局配置信息
    applyResultMap(resultMapId, returnType, argsIf(args), resultsIf(results), typeDiscriminator);
    return resultMapId;
  }

  /**
   * 生成 {@code method} 的ResultMapName
   * @param method 方法对象
   * @return
   * <ol>
   *     <li>如果有配置Results注解,拼装resultMapName=接口包名+类名+'.'+id属性值</li>
   *     <li>如果方法有参数 resultMapName=接口包名+类名+'.'+方法名+参数类型拼装字符串</li>
   *     <li>如果方法无参数resultMapName=接口包名+类名+'.'+方法名+'-void'</li>
   * </ol>
   */
  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<ResultMapping> 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<ResultMapping> 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<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)
              (discriminator.typeHandler() == UnknownTypeHandler.class ? null : discriminator.typeHandler());
      //获取TypeDiscriminator注解的Case注解数组
      Case[] cases = discriminator.cases();
      //定义鉴别器映射,用于存储Case注解的value,和resultMapId + "-" + value
      Map<String, String> 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
         * <ol>
         *     <li>STATEMENT:对应于Statement对象,有SQL注入的风险</li>
         *     <li>PREPARED:PreparedStatement,预编译处理</li>
         *     <li>CALLABLE:CallableStatement一般调用存储过程的时候使用</li>
         * </ol>
         */
        statementType = options.statementType();
        /**
         * ResultSet的常量,默认是DEFAULT
         * <ol>
         *     <li>DEFAULT:依赖驱动</li>
         *     <li>FORWARD_ONLY:结果集的游标只能向下滚动</li>
         *     <li>SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变</li>
         *     <li>SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变</li>
         * </ol>
         */
        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<? extends LanguageDriver> 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>[]
            // 或T[]的类型。其实也就是描述ParameterizedType类型以及TypeVariable类型的数组
            // ,即形如:classA<T>[][]、T[]等。
            //如果returnTypeParameter是GenericArrayType的子类或是其本身
          } else if (returnTypeParameter instanceof GenericArrayType) {
            //将returnTypeParameter强转为GenericArrayType类型赋值给componentType
            Class<?> componentType = (Class<?>) ((GenericArrayType) returnTypeParameter).getGenericComponentType();
            // (gcode issue #525) support List<byte[]>
            // 新建一个长度为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<? extends Annotation> sqlAnnotationType = getSqlAnnotationType(method);
      /**
       * 找出配置在 method中的SQL Provider 注解,就是
       *  {@link SelectProvider},{@link UpdateProvider},{@link InsertProvider},{@link DeleteProvider}
       */
      Class<? extends Annotation> 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<? extends Annotation> 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<? extends Annotation> 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<? extends Annotation> 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<? extends Annotation> chooseAnnotationType(Method method, Set<Class<? extends Annotation>> types) {
    //遍历注解列表
    for (Class<? extends Annotation> 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<ResultMapping> resultMappings) {
    //遍历Result注解数组
    for (Result result : results) {
      //ResultFlag枚举类型:ResultFlag.ID-表示是个表主键;ResultFlag.CONSTRUCTOR-表示是个构造函数参数
      //定义存放ResultFlag的集合
      List<ResultFlag> 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<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)
              ((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<ResultMapping> resultMappings) {
    //遍历Arg注解数组
    for (Arg arg : args) {
      //ResultFlag枚举类型:ResultFlag.ID-表示是个表主键;ResultFlag.CONSTRUCTOR-表示是个构造函数参数
      //定义存放ResultFlag的集合
      List<ResultFlag> 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<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>)
              (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;
  }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容