Mybatis核心处理层-初始化

建造者模式/BaseBuilder/xml

Posted by Claire on July 4, 2020

mybatis核心处理层-初始化

初始化主要依靠读取mybatis配置文件mybatis-config.xml 或者通过注解进行包扫描的方式,进行对象的注入

一、建造者模式-生成器模式

将一个复杂对象的构建过程与他的表示分离。一个复杂对象的构建也可以拆成若干简单步骤,用户指出了解对象类型和内容,不需要关注内部复杂的构造过程

1. 角色

  • 建造者(Builder):Builder 接口用于定义建造者构建产品对象的各部分的行为
  • 具体建造者(Concrete Builder): 直接创建产品对象的是具体建造者,包含建造方法,和获取对象的方法
  • 导演(Director): 该角色会通过调用具体建造者,创建需要的产品对象
  • 产品 (Product): 产品对象就需要建造的复杂对象

  • 建造者模式优点:
    • 导演不需要知道产品的内部细节,提供信息,让建造者完成建造
    • 将复杂产品的创造过程分散到不同的构造步骤中,实现对产品创建过程的精准控制,使过程更加清晰
    • 具体建造者之间相互独立,不同产品可以构建不同的建造者,不会影响代码稳定性,符合开放-封闭原则
  • 建造者模式缺点:
    • 不适合差异性大的产品,如果产品种类交过,内部变化复杂,则会增加系统的复杂性

2.mybatis中的运用

  • BaseBuilder

二、 BaseBuilder

mybatis初始化入口SqlSessionFactoryBuilder,构建了SqlSessionFactory,就有后续的初始化步骤

  • SqlSessionFactoryBuilder,内部各种build方法,接受不同参数,达到建造SqlSessionFactory的目的
    • 通过Reader或者InputStream的方式获取mybatis-config.xml文件
 public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      //xml的读取和参数映射,设置Configuratio对象,在mybatis中承载大部分基础配置参数
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

1.BaseBuilder 建造者

  • 上面的XMLConfigBuilder就是baseBuilder的实现类,这边的BaseBuilder就是建造者
//BaseBuilder基础属性
 //初始化过程核心对象  almost all in one
  protected final Configuration configuration;
 //配置中<typeAliases>标签定义别名
  protected final TypeAliasRegistry typeAliasRegistry;
  //配置中<typeHanlders>标签定义的已定义类型处理器
  protected final TypeHandlerRegistry typeHandlerRegistry;

三.XMLConfigBuilder 具体建造者

主要负责解析mybatis-config.xml 初始化Configuration

1.parse方法作为入口

 //入口
  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    //修改parse标志位
    parsed = true;
    //节点查找 evalNode  <configuration>   并解析
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

   private void parseConfiguration(XNode root) {
    try {
      // issue #117 read properties first
      //解析<properties>
      propertiesElement(root.evalNode("properties"));
      //解析<settings>
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      //解析<typeAliases>
      typeAliasesElement(root.evalNode("typeAliases"));
      //解析<plugins>
      pluginElement(root.evalNode("plugins"));
      //解析<objectFactory>
      objectFactoryElement(root.evalNode("objectFactory"));
      //解析<objectWrapperFactory>
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      // 解析<reflectorFactory>
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      //解析<environments>
      environmentsElement(root.evalNode("environments"));
      //解析<databaseIdProvider>
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      //解析<typeHandlers>
      typeHandlerElement(root.evalNode("typeHandlers"));
      //解析<mappers>
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

2.properties

private void propertiesElement(XNode context) throws Exception {
    if (context != null) {
      //记录properties标签的Name 和value 记录到 Properties对象中
      Properties defaults = context.getChildrenAsProperties();
      String resource = context.getStringAttribute("resource");
      String url = context.getStringAttribute("url");
      //resource 和 url 不能并存
      if (resource != null && url != null) {
        throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
      }
      if (resource != null) {
        defaults.putAll(Resources.getResourceAsProperties(resource));
      } else if (url != null) {
        defaults.putAll(Resources.getUrlAsProperties(url));
      }
      Properties vars = configuration.getVariables();
      if (vars != null) {
        defaults.putAll(vars);
      }
      parser.setVariables(defaults);
      configuration.setVariables(defaults);
    }
  }

3.settings

 private Properties settingsAsProperties(XNode context) {
    if (context == null) {
      return new Properties();
    }
    //读取settings 标签中的
    Properties props = context.getChildrenAsProperties();
    // Check that all settings are known to the configuration class
    //获取class的元信息 metaConfig
    MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
    for (Object key : props.keySet()) {
      //检验每一个字段是否可以设置值
      if (!metaConfig.hasSetter(String.valueOf(key))) {
        //有参数内部不能设置的抛异常
        throw new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");
      }
    }
    return props;
  }

4.typeAliases

private void typeAliasesElement(XNode parent) {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        //包下所有
        if ("package".equals(child.getName())) {
          String typeAliasPackage = child.getStringAttribute("name");
          configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
        } else {
          //指定类
          //xnode解析xml文档,前面有涉及过,以string读取内容
          String alias = child.getStringAttribute("alias");
          String type = child.getStringAttribute("type");
          try {
            Class<?> clazz = Resources.classForName(type);
            if (alias == null) {
              //无特殊别名,直接注册
              typeAliasRegistry.registerAlias(clazz);
            } else {
               //注册某个类的指定别名
              typeAliasRegistry.registerAlias(alias, clazz);
            }
          } catch (ClassNotFoundException e) {
            throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
          }
        }
      }
    }
  }

5.plugins

 private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        String interceptor = child.getStringAttribute("interceptor");
        //读取配置
        Properties properties = child.getChildrenAsProperties();
        //通过构造方法创建实例
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
        interceptorInstance.setProperties(properties);
        //添加拦截器
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }

6.objectFactory

 private void objectFactoryElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      //获取参数配置
      Properties properties = context.getChildrenAsProperties();
      //通过构造方法创建实例
      ObjectFactory factory = (ObjectFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      factory.setProperties(properties);
      //设置对象工厂
      configuration.setObjectFactory(factory);
    }
  }

7.objectWrapperFactory 与objectFactory相似

 private void objectWrapperFactoryElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      configuration.setObjectWrapperFactory(factory);
    }
  }

8.reflectorFactory 与objectFactory相似

 private void reflectorFactoryElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      ReflectorFactory factory = (ReflectorFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      configuration.setReflectorFactory(factory);
    }
  }

9.environments

//不同环境的environments --> environment
  private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
      if (environment == null) {
        //未指定environment 使用default
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
        String id = child.getStringAttribute("id");
        if (isSpecifiedEnvironment(id)) {
          //初始化事务工厂
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          //初始化数据源工厂
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          //获取数据源
          DataSource dataSource = dsFactory.getDataSource();
          //构建environment对象
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
  }

10.databaseIdProvider

DatabaseIdProvider接口有两个实现类:VendorDatabaseIdProvider & DefaultDatabaseIdProvider(过期)

 //通过databaseId区分多种数据库产品在SQL语言支持方面的差距,在初始化的时候确定使用数据库产品,再进行相应的解析,在家带databaseId和不带databaseId的SQL语句,如果SQL相同,带databaseId的权重大将被使用
  private void databaseIdProviderElement(XNode context) throws Exception {
    DatabaseIdProvider databaseIdProvider = null;
    if (context != null) {
      String type = context.getStringAttribute("type");
      // awful patch to keep backward compatibility
      if ("VENDOR".equals(type)) {
        //为兼容,修改type
        type = "DB_VENDOR";
      }
      //读取参数
      Properties properties = context.getChildrenAsProperties();
      //创建对象
      databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
      databaseIdProvider.setProperties(properties);
    }
    Environment environment = configuration.getEnvironment();
    if (environment != null && databaseIdProvider != null) {
      //databaseId绑定数据库
      String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
      configuration.setDatabaseId(databaseId);
    }
  }

11.typeHandlers

private void typeHandlerElement(XNode parent) {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          //类型转换包名
          String typeHandlerPackage = child.getStringAttribute("name");
          typeHandlerRegistry.register(typeHandlerPackage);
        } else {
          //指定Java类型和jdbc类型的处理类
          String javaTypeName = child.getStringAttribute("javaType");
          String jdbcTypeName = child.getStringAttribute("jdbcType");
          String handlerTypeName = child.getStringAttribute("handler");
          Class<?> javaTypeClass = resolveClass(javaTypeName);
          JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
          Class<?> typeHandlerClass = resolveClass(handlerTypeName);
          if (javaTypeClass != null) {
            if (jdbcType == null) {
              typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
            } else {
              typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
            }
          } else {
            typeHandlerRegistry.register(typeHandlerClass);
          }
        }
      }
    }
  }

12.mappers

private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          //扫描指定包,并注册指定包名
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          //三个不能同时存在
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            //加载resource,构建XMLMapperBuilder
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            //加载url ,加载XMLMapperBuilder
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null && mapperClass != null) {
            //加载类
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            //注册接口
            configuration.addMapper(mapperInterface);
          } else {
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }

四.XMLMapperBuilder 具体建造者

  • 由于继承自baseBuilder,那么核心入口就看parse
public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
      //尚未加载资源,基础mapper
      configurationElement(parser.evalNode("/mapper"));
      configuration.addLoadedResource(resource);
      bindMapperForNamespace();
    }
    //处理configurationElement里解析失败的resultMap节点
    parsePendingResultMaps();
    //处理configurationElement里解析失败的cacheRef节点
    parsePendingCacheRefs();
    //处理configurationElement里解析失败的SQL语句节点
    parsePendingStatements();
  }

  public XNode getSqlFragment(String refid) {
    return sqlFragments.get(refid);
  }

//下面就很熟悉,使用各种方法加载不同的节点
  private void configurationElement(XNode context) {
    try {
      //获取namespace属性
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.isEmpty()) {
        //如果为空异常
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      //解析cacheref
      cacheRefElement(context.evalNode("cache-ref"));
      //解析cache
      cacheElement(context.evalNode("cache"));
      //解析paramMap  已废弃
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      //解析resultMap
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      //解析sql语句  <sql>
      sqlElement(context.evalNodes("/mapper/sql"));
      //解析 <select> <delete> <update> <insert>
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
    }
  }

1. cache 节点,mybatis有一级二级缓存,二级缓存默认是不开启的

//XMLMapperBuilder
 private void cacheElement(XNode context) {
    if (context != null) {
      //获取cache的实现类  ,默认值PERPETUAL(前面有讲到唯一的实现)
      String type = context.getStringAttribute("type", "PERPETUAL");
      //找到type属性对应的cache
      Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
      //获取cache的eviction属性,默认LRU策略
      String eviction = context.getStringAttribute("eviction", "LRU");
      //找到对应eviction属性的cache装饰器类,LRUCache
      Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
      //获取 flushInterval属性,默认为null  ,对应装饰类SchedulingCache
      Long flushInterval = context.getLongAttribute("flushInterval");
      //获取cache节点的size属性,默认null
      Integer size = context.getIntAttribute("size");
      //获取cache节点readOnly属性,默认false
      boolean readWrite = !context.getBooleanAttribute("readOnly", false);
      //获取cache节点  blocking属性  对应装饰类 BlockingCache
      boolean blocking = context.getBooleanAttribute("blocking", false);
      Properties props = context.getChildrenAsProperties();
      // 通过以上属性 创建cache对象 并添加到Configuration.cache集合中
      builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
    }
  }
  //最后的MapperBuilderAssistant builderAssistant 是一个辅助类
  //useNewCache 创建新的cache对象,并将其添加到configuration.caches的列表中

// MapperBuilderAssistant 
 public Cache useNewCache(Class<? extends Cache> typeClass,
      Class<? extends Cache> evictionClass,
      Long flushInterval,
      Integer size,
      boolean readWrite,
      boolean blocking,
      Properties props) {
    //创建新的cache对象
    Cache cache = new CacheBuilder(currentNamespace)
        .implementation(valueOrDefault(typeClass, PerpetualCache.class))
        .addDecorator(valueOrDefault(evictionClass, LruCache.class))
        .clearInterval(flushInterval)
        .size(size)
        .readWrite(readWrite)
        .blocking(blocking)
        .properties(props)
        .build();
    //添加到configuration的caches中
    configuration.addCache(cache);
    currentCache = cache;
    return cache;
  }

  //Configuration
   protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
 //StrictMap 是Configuration的一个内部类,继承自HashMap对其实现了一些改变,主要在于get和put的时候
   public V put(String key, V value) {
      if (containsKey(key)) {
        throw new IllegalArgumentException(name + " already contains value for " + key
            + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
      }
      //区别在于,这边会对key做一个简短的处理,获取shortname
      if (key.contains(".")) {
        final String shortKey = getShortName(key);
        if (super.get(shortKey) == null) {
          //不存在直接添加
          super.put(shortKey, value);
        } else {
          //存在,添加为Ambiguity对象后添加
          super.put(shortKey, (V) new Ambiguity(shortKey));
        }
      }
      return super.put(key, value);
    }

    @Override
    public V get(Object key) {
      V value = super.get(key);
      if (value == null) {
        throw new IllegalArgumentException(name + " does not contain value for " + key);
      }
      if (value instanceof Ambiguity) {
        //如果是Ambiguity类型,证明key出现过重复情况,抛出异常
        throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
            + " (try using the full name including the namespace, or rename one of the entries)");
      }
      return value;
    }

2.CacheBuilder 采用建造者模式 构造Cache对象

public Cache build() {
    setDefaultImplementations();
    //根据实现类和id构造Cache实例 ,通过构造方法创建实例
    Cache cache = newBaseCacheInstance(implementation, id);
    setCacheProperties(cache);
    // issue #352, do not apply decorators to custom caches
    if (PerpetualCache.class.equals(cache.getClass())) {
      //是PerpetualCache实现类,为其添加装饰器cache类
      for (Class<? extends Cache> decorator : decorators) {
        //通过构造方法创建装饰器cache实例
        cache = newCacheDecoratorInstance(decorator, cache);
        //设置参数
        setCacheProperties(cache);
      }
      //设置标准装饰器
      cache = setStandardDecorators(cache);
    } else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
      //不是LoggingCache的子类,就直接创建一个LoggingCache
      cache = new LoggingCache(cache);
    }
    return cache;
  }

private Cache setStandardDecorators(Cache cache) {
    try {
      MetaObject metaCache = SystemMetaObject.forObject(cache);
      if (size != null && metaCache.hasSetter("size")) {
        metaCache.setValue("size", size);
      }
      if (clearInterval != null) {
        cache = new ScheduledCache(cache);
        ((ScheduledCache) cache).setClearInterval(clearInterval);
      }
      if (readWrite) {
        cache = new SerializedCache(cache);
      }
      //默认添加
      cache = new LoggingCache(cache);
      //默认添加
      cache = new SynchronizedCache(cache);
      if (blocking) {
        cache = new BlockingCache(cache);
      }
      return cache;
    } catch (Exception e) {
      throw new CacheException("Error building standard cache decorators.  Cause: " + e, e);
    }
  }

3.解析 cacheref 节点

  //解析cache-ref节点
  private void cacheRefElement(XNode context) {
    if (context != null) {
      //将namespace2和namespace1绑定,存入configuration   protected final Map<String, String> cacheRefMap = new HashMap<>();
      configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
      //创建cacheRefResolver
      CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
      try {
        //解析cache 引用,最终依靠MapperBuilderAssistant辅助类
        //设置currentCache = cache;
        //设置unresolvedCacheRef = false;
        cacheRefResolver.resolveCacheRef();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteCacheRef(cacheRefResolver);
      }
    }
  }

//configuration
  public void addCacheRef(String namespace, String referencedNamespace) {
    cacheRefMap.put(namespace, referencedNamespace);
  }

//MapperBuilderAssistant
 public Cache useCacheRef(String namespace) {
    if (namespace == null) {
      throw new BuilderException("cache-ref element requires a namespace attribute.");
    }
    try {
      unresolvedCacheRef = true;
      Cache cache = configuration.getCache(namespace);
      if (cache == null) {
        throw new IncompleteElementException("No cache for namespace '" + namespace + "' could be found.");
      }
      currentCache = cache;
      unresolvedCacheRef = false;
      return cache;
    } catch (IllegalArgumentException e) {
      throw new IncompleteElementException("No cache for namespace '" + namespace + "' could be found.", e);
    }
  }

4. 解析resultMap节点

通常一个resultMap体中都有很多行,javatype和jdbctype的映射关系,会被映射为ResultMapping

//内部属性

  private Configuration configuration;
  //节点property属性
  private String property;
  //节点column属性
  private String column;
  //对应节点的javaType属性,可能是java类名,或者一个类型的别名
  private Class<?> javaType;
  //jdbc类型
  private JdbcType jdbcType;
  //类型处理器
  private TypeHandler<?> typeHandler;
  private String nestedResultMapId;
  private String nestedQueryId;
  private Set<String> notNullColumns;
  private String columnPrefix;
  //处理后的标志,共两个,id constructor
  private List<ResultFlag> flags;
  //对应节点的column属性拆分后生成的结果
  private List<ResultMapping> composites;
  //resultSet属性
  private String resultSet;
  private String foreignColumn;
  //是否延迟加载
  private boolean lazy;

  //通过建造者模式设置以上参数 内部类Builder

多个resultMappings形成一个resultMap

//resultmap

  private Configuration configuration;
  //resultMap节点id属性
  private String id;
  //resultmap节点type属性
  private Class<?> type;
  //多个字段的映射关系
  private List<ResultMapping> resultMappings;
  //记录带有ID标志的映射关系
  private List<ResultMapping> idResultMappings;
  //记录带有constructor标志的映射关系
  private List<ResultMapping> constructorResultMappings;
  //记录不带有constructor的映射关系
  private List<ResultMapping> propertyResultMappings;
  //记录所有映射关系中设计的column属性的集合
  private Set<String> mappedColumns;
  //
  private Set<String> mappedProperties;
  //对应 discriminator节点
  private Discriminator discriminator;
  //存在resultmap 不存在resultset
  private boolean hasNestedResultMaps;
  //是否含有嵌套查询
  private boolean hasNestedQueries;
  //是否开启自动映射
  private Boolean autoMapping;

resultMap也通过建造者模式Builder的形式初始化以上属性 ResultMapping 内部有一个Builder类,采用建造者模式,实现数据整理和数据校验 XMLMapperBuilder 中处理resultMap节点

 //处理resultMap节点
  private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) {
    ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
    //获取type属性
    String type = resultMapNode.getStringAttribute("type",
        resultMapNode.getStringAttribute("ofType",
            resultMapNode.getStringAttribute("resultType",
                resultMapNode.getStringAttribute("javaType"))));
    Class<?> typeClass = resolveClass(type);
    if (typeClass == null) {
      typeClass = inheritEnclosingType(resultMapNode, enclosingType);
    }
    Discriminator discriminator = null;
    List<ResultMapping> resultMappings = new ArrayList<>(additionalResultMappings);
    List<XNode> resultChildren = resultMapNode.getChildren();
    //遍历子节点
    for (XNode resultChild : resultChildren) {
      //节点是 constructor 类型
      if ("constructor".equals(resultChild.getName())) {
        processConstructorElement(resultChild, typeClass, resultMappings);
      } else if ("discriminator".equals(resultChild.getName())) {
        //节点是discriminator类型
        discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
      } else {
        //处理id result  association collection
        List<ResultFlag> flags = new ArrayList<>();
        if ("id".equals(resultChild.getName())) {
          //如果是ID,向集合中添加ResultFlag.ID
          flags.add(ResultFlag.ID);
        }
        //创建resultMapping对象,并添加到resultMappings集合中保存
        resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
      }
    }
    //id属性
    String id = resultMapNode.getStringAttribute("id",
            resultMapNode.getValueBasedIdentifier());
    //extends属性
    String extend = resultMapNode.getStringAttribute("extends");
    //是否自动映射,如果true则开启自动映射功能,自动查找
    Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
    //自动映射
    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    try {
      return resultMapResolver.resolve();
    } catch (IncompleteElementException e) {
      configuration.addIncompleteResultMap(resultMapResolver);
      throw e;
    }
  }


  private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) {
    String property;
    //包含constructor
    if (flags.contains(ResultFlag.CONSTRUCTOR)) {
      //name属性 -> property
      property = context.getStringAttribute("name");
    } else {
      //property属性
      property = context.getStringAttribute("property");
    }
    String column = context.getStringAttribute("column");
    String javaType = context.getStringAttribute("javaType");
    String jdbcType = context.getStringAttribute("jdbcType");
    String nestedSelect = context.getStringAttribute("select");
    String nestedResultMap = context.getStringAttribute("resultMap", () ->
        processNestedResultMappings(context, Collections.emptyList(), resultType));
    String notNullColumn = context.getStringAttribute("notNullColumn");
    String columnPrefix = context.getStringAttribute("columnPrefix");
    String typeHandler = context.getStringAttribute("typeHandler");
    String resultSet = context.getStringAttribute("resultSet");
    String foreignColumn = context.getStringAttribute("foreignColumn");
    boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
    Class<?> javaTypeClass = resolveClass(javaType);
    Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
    //构建resultMapping对象
    return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
  }

resultMap解析,包括解析constructor节点、association collection case 节点、discriminator节点

5.解析sql节点

五.XMLStatementBuilder 具体建造者

  • SqlSource 数据源 : DynamicSqlSource/ProviderSqlSource/RawSqlSource/StaticSqlSource
  • 解析SQL节点的入口
public void parseStatementNode() {
    //获取id
    String id = context.getStringAttribute("id");
    //获取databaseId
    String databaseId = context.getStringAttribute("databaseId");
    //如果 databaseId 与当前使用类型不匹配,就不解析
    if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
      return;
    }

    //获取多种查询属性配置
    String nodeName = context.getNode().getNodeName();
    //SQL类型
    SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
    boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
    boolean useCache = context.getBooleanAttribute("useCache", isSelect);
    boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);


    // Include Fragments before parsing
    //解析<include>节点
    XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
    includeParser.applyIncludes(context.getNode());

    String parameterType = context.getStringAttribute("parameterType");
    Class<?> parameterTypeClass = resolveClass(parameterType);

    String lang = context.getStringAttribute("lang");
    LanguageDriver langDriver = getLanguageDriver(lang);

    // Parse selectKey after includes and remove them.
    //解析<selectkey>节点
    processSelectKeyNodes(id, parameterTypeClass, langDriver);

    // Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
    KeyGenerator keyGenerator;
    String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
    //检测sql中是否配置了selectkey ,sql节点的useGeneratedKeys 属性值
    keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
    if (configuration.hasKeyGenerator(keyStatementId)) {
      keyGenerator = configuration.getKeyGenerator(keyStatementId);
    } else {
      keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
          configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
          ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
    }

    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    Integer fetchSize = context.getIntAttribute("fetchSize");
    Integer timeout = context.getIntAttribute("timeout");
    String parameterMap = context.getStringAttribute("parameterMap");
    String resultType = context.getStringAttribute("resultType");
    Class<?> resultTypeClass = resolveClass(resultType);
    String resultMap = context.getStringAttribute("resultMap");
    String resultSetType = context.getStringAttribute("resultSetType");
    ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
    if (resultSetTypeEnum == null) {
      resultSetTypeEnum = configuration.getDefaultResultSetType();
    }
    //获取 keyProperty  keyColumn   resultSets
    String keyProperty = context.getStringAttribute("keyProperty");
    String keyColumn = context.getStringAttribute("keyColumn");
    String resultSets = context.getStringAttribute("resultSets");

    //创建MappedStatement  并添加到mapped statements集合中
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }

1.解析 include 节点

 //入口
  public void applyIncludes(Node source) {
    Properties variablesContext = new Properties();
    Properties configurationVariables = configuration.getVariables();
    Optional.ofNullable(configurationVariables).ifPresent(variablesContext::putAll);
    applyIncludes(source, variablesContext, false);
  }

  /**
   * Recursively apply includes through all SQL fragments.
   *
   * @param source
   *          Include node in DOM tree
   * @param variablesContext
   *          Current context for static variables with values
   *          递归调用,替换include中的SQL片段,并且将占位符替换成真正的参数
   */
  private void applyIncludes(Node source, final Properties variablesContext, boolean included) {
    if (source.getNodeName().equals("include")) {
      //获取refid对应指向的SQL片段 , 返回深克隆的Node对象
      Node toInclude = findSqlFragment(getStringAttribute(source, "refid"), variablesContext);
      //将解析到的参数键值添加到variablesContext中,用于替换
      Properties toIncludeContext = getVariablesContext(source, variablesContext);
      //递归处理include标签,内部sql节点可能会使用include继续应用其他SQL
      applyIncludes(toInclude, toIncludeContext, true);
      if (toInclude.getOwnerDocument() != source.getOwnerDocument()) {
        toInclude = source.getOwnerDocument().importNode(toInclude, true);
      }
      //将获取的SQL节点替换include节点
      source.getParentNode().replaceChild(toInclude, source);
      while (toInclude.hasChildNodes()) {
        //将内部的子SQL频段添加到SQL前面
        toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude);
      }
      //删除SQL节点
      toInclude.getParentNode().removeChild(toInclude);
    } else if (source.getNodeType() == Node.ELEMENT_NODE) {
      if (included && !variablesContext.isEmpty()) {
        // replace variables in attribute values
        NamedNodeMap attributes = source.getAttributes();
        //遍历子节点
        for (int i = 0; i < attributes.getLength(); i++) {
          Node attr = attributes.item(i);
          //使用之前解析到的参数替换占位符
          attr.setNodeValue(PropertyParser.parse(attr.getNodeValue(), variablesContext));
        }
      }
      NodeList children = source.getChildNodes();
      for (int i = 0; i < children.getLength(); i++) {
        applyIncludes(children.item(i), variablesContext, included);
      }
    } else if (included && (source.getNodeType() == Node.TEXT_NODE || source.getNodeType() == Node.CDATA_SECTION_NODE)
        && !variablesContext.isEmpty()) {
      // replace variables in text node
      source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
    }
  }

2.解析selectKey 节点

private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
    List<XNode> selectKeyNodes = context.evalNodes("selectKey");
    if (configuration.getDatabaseId() != null) {
      parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
    }
    parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
    removeSelectKeyNodes(selectKeyNodes);
  }

  private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
    for (XNode nodeToHandle : list) {
      String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
      String databaseId = nodeToHandle.getStringAttribute("databaseId");
      if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
        parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
      }
    }
  }

  private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
    //获取 resultType statementType keyProperty keyColumn order 等属性
    String resultType = nodeToHandle.getStringAttribute("resultType");
    Class<?> resultTypeClass = resolveClass(resultType);
    StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
    String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
    boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));

    // defaults
    boolean useCache = false;
    boolean resultOrdered = false;
    KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
    Integer fetchSize = null;
    Integer timeout = null;
    boolean flushCache = false;
    String parameterMap = null;
    String resultMap = null;
    ResultSetType resultSetTypeEnum = null;
      //通过languageDriver创建SQLSOURCE
    // languageDriver 可以通过mybatis-config.xml进行配置,也可以自定义实现,可以由defaultScriptingLanguage指定
    //languageDriver 有两个实现类: XMLLanguageDriver RawLanguageDriver
    SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
    //<selectKey 里面只能配置SELECT语句
    SqlCommandType sqlCommandType = SqlCommandType.SELECT;
     //通过辅助类创建mappedStatement,并添加到mappedstatements集合中 ,类型是StrictMap
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);

    id = builderAssistant.applyCurrentNamespace(id, false);

    MappedStatement keyStatement = configuration.getMappedStatement(id, false);
    //床建select key 节点对应的key generator 添加到Configuration的key generators集合中,类型也是StrictMap
    configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
  }

六、绑定Mapper接口

七、处理imcomplete*接口