mybatis 解析xml流程

前言

使用mybatis的时候基本上都需要写一个mapper.xml以及对应的Mapper.java。在mapper.xml中写sql的时候还需要对应Mapper.java中的某个方法,常规操作知道如何弄,但是你知道最后mapper.xml中的等节点,具体是保存在XNode中,主要作用是解析出这些节点的属性,然后通过MapperBuilderAssistant将其保存在Configuration对象中。
XNode:保存了xml的节点,用于解析节点属性。比如获取等节点对应的Java对象。
Configuration:这个类真是个集大成者,包含mapper.xml中的cacheresultMapsparameterMaps等,基本上就是mapper.xml对应的Java对象。

流程一装载xml

装载mapper.xml涉及SqlSessionFactoryBeanXMLMapperBuilder以及XPathParser。首先看的是SqlSessionFactoryBeanbuildSqlSessionFactory方法,为了方便大家看源码,我只把主要的流程保留了下来,其他旁枝末节都删掉了。

 protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
   ....
    if (!isEmpty(this.mapperLocations)) {
      // resource 就是mapper.xml文件,这里遍历所有的mapper.xml文件
      for (Resource mapperLocation : this.mapperLocations) {
        if (mapperLocation == null) {
          continue;
        }

        try {
          //根据configuration以及mapper.xml文件的输入流创建XMLMapperBuilder 
          XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
              configuration, mapperLocation.toString(), configuration.getSqlFragments());
          // 主要是解析xml文件
          xmlMapperBuilder.parse();
        } catch (Exception e) {
          throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
        } finally {
          ErrorContext.instance().reset();
        }

    return this.sqlSessionFactoryBuilder.build(configuration);
  }

接下来就是看XMLMapperBuilder的构造方法。这个构造方法主要就是根据mapper.xml文件输入流构造XPathParser,到这里某个mapper.xml已经装载到XMLMapperBuilder

public class XMLMapperBuilder extends BaseBuilder {
  private final XPathParser parser;
  private final MapperBuilderAssistant builderAssistant;
  private final Map sqlFragments;
...
 public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map sqlFragments) {
    // 根据xml文件输入流构造XPathParser
    this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
        configuration, resource, sqlFragments);
  }

}

流程二解析xml各节点。

这一步涉及到XMLMapperBuilderXMLStatementBuilderXPathParserXNode
首先看XMLMapperBuilder,其主要作用获取xml的节点信息。获取节点信息的主要目的是构造对应节点的Java对象。比如 所有节点 buildStatementFromContext(context.evalNodes("select|insert|update|delete")); } catch (Exception e) { throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e); } } private void buildStatementFromContext(List list) { if (configuration.getDatabaseId() != null) { buildStatementFromContext(list, configuration.getDatabaseId()); } buildStatementFromContext(list, null); } private void buildStatementFromContext(List list, String requiredDatabaseId) { // XNode 代表一个| | |节点中的信息,然后交给MapperBuilderAssistant创建MappedStatement

public void parseStatementNode() {
    String id = context.getStringAttribute("id");
    String databaseId = context.getStringAttribute("databaseId");

    if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
      return;
    }
    //主要就是获取节点属性
    Integer fetchSize = context.getIntAttribute("fetchSize");
    Integer timeout = context.getIntAttribute("timeout");
    String parameterMap = context.getStringAttribute("parameterMap");
    String parameterType = context.getStringAttribute("parameterType");
    Class parameterTypeClass = resolveClass(parameterType);
    String resultMap = context.getStringAttribute("resultMap");
    String resultType = context.getStringAttribute("resultType");
    String lang = context.getStringAttribute("lang");
    LanguageDriver langDriver = getLanguageDriver(lang);
    .....
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered, 
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }

流程三构造MappedStatement

MappedStatement就是对应