MyBatis源码初识二 加载mapper.xml文件

源码流程图

在这里插入图片描述

源码

加载xml资源代码

private void loadXmlResource() {
  //当前类没有加载过资源,进行加载
  if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
  	//得到xml的物理路径
    String xmlResource = type.getName().replace('.', '/') + ".xml";
    //根据物理路径获取文件流
    InputStream inputStream = type.getResourceAsStream("/" + xmlResource);
    if (inputStream == null) {
      // 没有找到,到classpath再次查找
      try {
        inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
      } catch (IOException e2) {
      }
    }
    if (inputStream != null) {
      //如果文件存在,解析xml
      XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
      //开始解析
      xmlParser.parse();
    }
  }
}

解析xml xmlParser.parse()

public void parse() {
  //判断资源是否加载过
  if (!configuration.isResourceLoaded(resource)) {
    //解析xml中的mapper节点(重点)
    configurationElement(parser.evalNode("/mapper"));
    //记录加载记录
    configuration.addLoadedResource(resource);
	//绑定mapper和namespace
    bindMapperForNamespace();
  }

  parsePendingResultMaps();
  parsePendingCacheRefs();
  parsePendingStatements();
}

解析mapper节点 configurationElement

private void configurationElement(XNode context) {
 try {
    //获取mapper节点的namespace属性
    String namespace = context.getStringAttribute("namespace");
    //如果为空,抛异常
    if (namespace == null || namespace.equals("")) {
      throw new BuilderException("Mapper's namespace cannot be empty");
    }
    //判断namespace和类名是否相同,如果不相同,抛异常
    builderAssistant.setCurrentNamespace(namespace);
    //如果配置了此节点,记录当前mapper应用二级缓存
    cacheRefElement(context.evalNode("cache-ref"));
    //如果配置了二级缓存,构造缓存对象
    cacheElement(context.evalNode("cache"));
    
    parameterMapElement(context.evalNodes("/mapper/parameterMap"));
    //解析resultMap节点
    resultMapElements(context.evalNodes("/mapper/resultMap"));
    //解析sql节点
    sqlElement(context.evalNodes("/mapper/sql"));
    //解析select/insert/update/delete节点
    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);
  }
}

二级缓存

cacheElement 解析二级缓存

private void cacheElement(XNode context) {
  if (context != null) {
    //解析cache节点的type属性
    String type = context.getStringAttribute("type", "PERPETUAL");
    //根据type的String获取class类型
    Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
    //获取缓存过期策略:默认是LRU
    String eviction = context.getStringAttribute("eviction", "LRU");
    Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
    //刷新间隔
    Long flushInterval = context.getLongAttribute("flushInterval");
    //引用数目
    Integer size = context.getIntAttribute("size");
    //只读(true:返回同一个对象,false:序列化后返回新对象)
    boolean readWrite = !context.getBooleanAttribute("readOnly", false);
    boolean blocking = context.getBooleanAttribute("blocking", false);
    Properties props = context.getChildrenAsProperties();
    //构造缓存对象,添加到caches中
    builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
  }
}

useNewCache 构造二级缓存

public Cache useNewCache(Class<? extends Cache> typeClass,
    Class<? extends Cache> evictionClass,
    Long flushInterval,
    Integer size,
    boolean readWrite,
    boolean blocking,
    Properties props) {
    //构造缓存对象
  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.addCache(cache);
  currentCache = cache;
  return cache;
}

解析resultMap

private void resultMapElements(List<XNode> list) throws Exception {
  // 拿到所有<resultMap> 解析
  for (XNode resultMapNode : list) {
    try {
      resultMapElement(resultMapNode);
    } catch (IncompleteElementException e) {
      // ignore, it will be retried
    }
  }
}
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) throws Exception {
  ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
  // 获取对应类名
  String type = resultMapNode.getStringAttribute("type",
      resultMapNode.getStringAttribute("ofType",
          resultMapNode.getStringAttribute("resultType",
              resultMapNode.getStringAttribute("javaType"))));
  // 获取类名对应的class
  Class<?> typeClass = resolveClass(type);
  if (typeClass == null) {
    typeClass = inheritEnclosingType(resultMapNode, enclosingType);
  }
  Discriminator discriminator = null;
  //记录解析的每个resultMapping节点
  List<ResultMapping> resultMappings = new ArrayList<>();
  resultMappings.addAll(additionalResultMappings);
  //获取resultMap下的所有节点
  List<XNode> resultChildren = resultMapNode.getChildren();
  for (XNode resultChild : resultChildren) {
    if ("constructor".equals(resultChild.getName())) {
      processConstructorElement(resultChild, typeClass, resultMappings);
    } else if ("discriminator".equals(resultChild.getName())) {
      discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
    } else {
      List<ResultFlag> flags = new ArrayList<>();
      //如果节点名是id,记录主键
      if ("id".equals(resultChild.getName())) {
        flags.add(ResultFlag.ID);
      }
      // 解析属性,构造成ResultMapping放到集合中
      resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
    }
  }
  String id = resultMapNode.getStringAttribute("id",
          resultMapNode.getValueBasedIdentifier());
  String extend = resultMapNode.getStringAttribute("extends");
  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;
  }
}

解析sql节点

private void sqlElement(List<XNode> list, String requiredDatabaseId) {
  for (XNode context : list) {
    String databaseId = context.getStringAttribute("databaseId");
    String id = context.getStringAttribute("id");
    id = builderAssistant.applyCurrentNamespace(id, false);
    if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
      //sql对应的node节点放到集合中
      sqlFragments.put(id, context);
    }
  }
}

解析select|insert|update|delete

构造Statement

//buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
  //循环select|delte|insert|update节点
  for (XNode context : list) {
    //xmlStatement构造器
    final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
    try {
      //根据xml节点构造xmlStatement
      statementParser.parseStatementNode();
    } catch (IncompleteElementException e) {
      configuration.addIncompleteStatement(statementParser);
    }
  }
}

将节点解析成Statement

public void parseStatementNode() {
  //获取id
  String id = context.getStringAttribute("id");
  //获取databaseId
  String databaseId = context.getStringAttribute("databaseId");
  //判断是否是当前运行的
  if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
    return;
  }
  //获得节点名称:select|insert|update|delete
  String nodeName = context.getNode().getNodeName();
  //根据节点名称获取SqlCommandType 
  SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
  //判断是不是select
  boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
  //执行当前方法,是否清除cache(select默认是false)
  boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
  //执行此方法,是否使用catch(select默认是true)
  boolean useCache = context.getBooleanAttribute("useCache", isSelect);
  boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
  //解析sql片段
  XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
  includeParser.applyIncludes(context.getNode());
  //传参类型
  String parameterType = context.getStringAttribute("parameterType");
  // 把参数类型字符串转化为class
  Class<?> parameterTypeClass = resolveClass(parameterType);
  String lang = context.getStringAttribute("lang");
  LanguageDriver langDriver = getLanguageDriver(lang);
  processSelectKeyNodes(id, parameterTypeClass, langDriver);
  //主键生成策略
  KeyGenerator keyGenerator;
  //生成当前statementId
  String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
  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 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");
  //解析resultType
  String resultType = context.getStringAttribute("resultType");
  Class<?> resultTypeClass = resolveClass(resultType);
  //解析resultMap
  String resultMap = context.getStringAttribute("resultMap");
  String resultSetType = context.getStringAttribute("resultSetType");
  ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
  if (resultSetTypeEnum == null) {
    resultSetTypeEnum = configuration.getDefaultResultSetType();
  }
  String keyProperty = context.getStringAttribute("keyProperty");
  String keyColumn = context.getStringAttribute("keyColumn");
  String resultSets = context.getStringAttribute("resultSets");
  //构建mappedStatment对象
  builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
      fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
      resultSetTypeEnum, flushCache, useCache, resultOrdered,
      keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}

创建createSqlSource

public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
  XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
  return builder.parseScriptNode();
}

解析脚本

public SqlSource parseScriptNode() {
  //解析动态sql节点
  MixedSqlNode rootSqlNode = parseDynamicTags(context);
  SqlSource sqlSource;
  if (isDynamic) {
    // 动态Sql源
    sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
  } else {
    // 静态Sql源, 它会在这里解析
    sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
  }
  return sqlSource;
}

真正开始解析

protected MixedSqlNode parseDynamicTags(XNode node) {
  List<SqlNode> contents = new ArrayList<>();
  NodeList children = node.getNode().getChildNodes();  			      	
  //获得子节点
  for (int i = 0; i < children.getLength(); i++) {
    XNode child = node.newXNode(children.item(i));
    //如果节点是文本,转成TextSqlNode 
    if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
      String data = child.getStringBody(""); 
      //将文本内容转成TextSqlNode节点
      TextSqlNode textSqlNode = new TextSqlNode(data);
      //判断是否是动态sql(包含${})
      if (textSqlNode.isDynamic()) {
        contents.add(textSqlNode);
        isDynamic = true;
      } else {
      	//如果不包含,当前节点转为StaticTextSqlNode
        contents.add(new StaticTextSqlNode(data));
      }
    } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) {
      //如果子节点是个节点,递归解析
      String nodeName = child.getNode().getNodeName();
      //获取当前节点的处理类,用处理类转换(如WhereHandler、ForEachHandler)
      NodeHandler handler = nodeHandlerMap.get(nodeName);
      if (handler == null) {
        throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
      }
      handler.handleNode(child, contents);
      isDynamic = true;
    }
  }
  return new MixedSqlNode(contents);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值