Mybaits源码分析(1) 构建SqlSessionFactory

1 读取 Mybatis-config 配置文件
InputStream inputStream = new FileInputStream
                ("D:\\Users\\Administrator\\IdeaProjects\\mybatis_demo\\src\\main\\resources\\Mybatis-config.xml");

2 构建 SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

3 进入 build() 方法内部
  • 类 : SqlSessionFactoryBuilder
  • 作用 : 构建SqlSessionFactory
  • 方法: build()
public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      //XmlConfigBuild  构造器
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

3.1 进入 XMLConfigBuilder 构造器内部
  • 类 : XMLConfigBuilder
  • 作用 : 负责解析mybatis-config.xml
  • 构造器
public class XMLConfigBuilder extends BaseBuilder {
  // 是否解析过
  private boolean parsed;
  //解析器对象
  private XPathParser parser;
  //环境
  private String environment;
  private ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
	//构造器内部创建XPathParser对象
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }
}

3.1.1 进入 XPathParser 构造器内部
  • 类 : XPathParser
  • 作用 : 读取 xml 文件解析为文档对象
  • 构造器
public class XPathParser {
  //解析后的文档对象
  private Document document;
  //是否有效
  private boolean validation;
  //xml的实体解析器
  private EntityResolver entityResolver;
  private Properties variables;
  //Xml文件路径
  private XPath xpath;
  
  public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
	//通用构造器,赋默认值
    commonConstructor(validation, variables, entityResolver);
    //解析xml文件为document对象方法
    this.document = createDocument(new InputSource(inputStream));
  }
}

3.1.2 进入 createDocument() 方法
  • 类 : XPathParser
  • 方法 : createDocument()
  • 作用 : 解析 xml 文件为 Document 对象后赋值到 document 属性中
 private Document createDocument(InputSource inputSource) {
    // important: this must only be called AFTER common constructor
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      //1 是否验证xml文件,这个验证是DTD验证
      factory.setValidating(validation);
      //2 是否支持xml命名空间
      factory.setNamespaceAware(false);
      //3 是否忽略注释 
      factory.setIgnoringComments(true);
      //4 是否忽略元素中的空白
      factory.setIgnoringElementContentWhitespace(false);
      //5 是否将CDATA节点转换为Text节点,并将其附加到相邻(如果有)的Text节点
      factory.setCoalescing(false);
      //6 是否扩展实体引用节点
      factory.setExpandEntityReferences(true);
      //创建文档构造器实例
      DocumentBuilder builder = factory.newDocumentBuilder();
      //  封装实体解析器
      builder.setEntityResolver(entityResolver);
      //  封装错误处理器
      builder.setErrorHandler(new ErrorHandler() {
        @Override
        public void error(SAXParseException exception) throws SAXException {
          throw exception;
        }

        @Override
        public void fatalError(SAXParseException exception) throws SAXException {
          throw exception;
        }

        @Override
        public void warning(SAXParseException exception) throws SAXException {
        }
      });
      //使用文档构造器解析xml,并返回解析后的document对象
      return builder.parse(inputSource);
    } catch (Exception e) {
      throw new BuilderException("Error creating document instance.  Cause: " + e, e);
    }
  }

3.1 总结 : 此时 XMLConfigBuilder 对象已经产生
  • 3.1 过程完成了解析mybatis-config.xml —>document对象
  • XmlConfigBuilder 属性对象中 XPathParser 属性对象中 document 属性中已经封装了 mybatis-config.xml 配置文件
  • 接下来将在 3 中 XMLConfigBuilder 对象调用 parse() 方法将 document 配置到Configuration 对象中

3.2 回到 parse() 方法
  • 类 : XMLConfigBuilder
  • 方法 : parse()
  • 作用 : 解析 document 对象 (mybatis-config.xml) 封装到 Configuration 对象中
public class XMLConfigBuilder extends BaseBuilder {
  // 是否解析过
  private boolean parsed;
  //解析器对象
  private XPathParser parser;
  						...
 public Configuration parse() {
 	//判断是否解析过,默认为false
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    //标记解析记录
    parsed = true;
    //解析document对象中<configuration>标签中内容到Configuration对象中
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

3.2.1 parseConfiguration() 解析 document 对象到 Configuration 对象过程
  • 类 : XMLConfigBuilder
  • 方法 : parseConfiguration()
  • 作用 : 每个方法都是解析各个节点封装到 Configuration 对象中的过程
  private void parseConfiguration(XNode root) {
    try {
      Properties settings = settingsAsPropertiess(root.evalNode("settings"));
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

3.2.2 mapperElement() 重点看一下解析 Mapper.xml 文件过程
  • 类 : XMLConfigBuilder
  • 方法 : mapperElement()
  • 作用 : 查找 mybatis-config 中配置的< mappers/ >标签,即 Mapper.xml
  private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
      	//配置的是 <package/> 标签
        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");
          //配置的是 <mapper resource=""/> 标签
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
           //配置的是 <mapper url=""/> 标签
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
           //配置的是 <mapper class=""/> 标签
          } 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.");
          }
        }
      }
    }
  }

3.2 总结 :
  • 3.2 将解析 mybatis-config.xml 产生的document 对象配置到 Configuration 对象中
  • 接下来开始扫描 Mapper.xml 文件并解析封装到 Configuration 对象中

4.1 addMappers() 使用包扫描时注册接口方法
  • 类 : Configuration
  • 方法 : addMappers()
  • 作用 : 注册和获取Mapper对象的代理
public void addMappers(String packageName) {
    //此处是委派模式,查看具体实现
    mapperRegistry.addMappers(packageName);
  }

4.1.1 addMapper() 具体注册接口方法
  • 类 : MapperRegistry
  • 方法 : addMapper()
  • 作用 : 注册接口,为该接口生成代理对象
  • 注 : 此处省略扫描包内所有接口的过程 , 直接看注册接口具体实现
public class MapperRegistry {
  //配置对象
  private final Configuration config;
  //已注册过的接口集合 
  //Key:接口的字节码对象  Value:该接口的代理工厂
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
  
  public <T> void addMapper(Class<T> type) {
  	//判断该类是否是接口
    if (type.isInterface()) {
    	//是否已经注册过该接口
      if (hasMapper(type)) {
      	//注册过,抛异常
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      //标记未完成加载标识
      boolean loadCompleted = false;
      try {
        //注册接口到已注册接口集合中
        knownMappers.put(type, new MapperProxyFactory<T>(type));
        //创建解析 SqlMapper或接口上注解 的解析器
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        //解析接口上的注解或者加载mapper配置文件生成mappedStatement
        parser.parse();
        //标记解析完成标识
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }
}  

4.1.1.1 parse() 解析 Mapper.xml 方法
  • 类 : MapperAnnotationBuilder
  • 方法 : parse()
  • 作用 : 解析映射文件或者注解方法
public class MapperAnnotationBuilder {

 private final Set<Class<? extends Annotation>> sqlAnnotationTypes = new HashSet<Class<? extends Annotation>>();
 private final Set<Class<? extends Annotation>> sqlProviderAnnotationTypes = new HashSet<Class<? extends Annotation>>();
 //配置对象
 private Configuration configuration;
 // SQLMapper.xml 映射文件构建助手
 private MapperBuilderAssistant assistant;
 //解析的接口字节码对象
 private Class<?> type;

 public void parse() {
  //该接口完全限定名
   String resource = type.toString();
   //该接口未加载到配置对象中
   if (!configuration.isResourceLoaded(resource)) {
    //载入该接口对应的SQLMapper.xml资源
     loadXmlResource();
     //将该接口加入已加载列表
     configuration.addLoadedResource(resource);
     //设置当前接口命名空间
     assistant.setCurrentNamespace(type.getName());
     parseCache();
     parseCacheRef();
     //获取该接口所有方法
     Method[] methods = type.getMethods();
     for (Method method : methods) {
       try {
         // issue #237
         //非桥接方法
         if (!method.isBridge()) {
           //注解方式解析方法
           parseStatement(method);
         }
       } catch (IncompleteElementException e) {
         configuration.addIncompleteMethod(new MethodResolver(this, method));
       }
     }
   }
   parsePendingMethods();
 }
 }
4.1.1.2 loadXmlResource() 加载Mapper.xml资源方法
private void loadXmlResource() {
 	//验证是否加载过该xml文件
    if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
      //通过接口名称拼接出对应的Mapper文件路径
      String xmlResource = type.getName().replace('.', '/') + ".xml";
      InputStream inputStream = null;
      try {
      	//将Mapper.xml文件读取到流中
        inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
      } catch (IOException e) {
        // ignore, resource is not required
      }
      if (inputStream != null) {
        //创建Mapper.xml 配置文件构造器
        XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
        xmlParser.parse();
      }
    }
  }
4.1.1.2.1 XMLMapperBuilder 构造器
  • 类 : XMLMapperBuilder
  • 方法 : 构造器
  • 对比 :
  1. XMLConfigBuilder : 读取 mybatis-config.xml 到 XPathParser 对象的 document 中
  2. XMLMapperBuilder : 读取 Mapper.xml 到 XPathParser 对象的 document 中
  • 相同点 : 都通过 prase() 方法解析 document 对象到 configuration 对象中
public class XMLMapperBuilder extends BaseBuilder {
  //xml 文件解析器
  private XPathParser parser;
  //Mapper.xml构建助手
  private MapperBuilderAssistant builderAssistant;
  //解析mapper.xml后的sql片段
  // Key:当前mapper的namespace+"."+<sql>标签中的id属性 Value为sql这个XNode本身
  private Map<String, XNode> sqlFragments;
  private String resource;

public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
    //内部依然创建XPathParser对象
    this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
        configuration, resource, sqlFragments);
  }

4.1.1.2.1.1 进入 XPathParser 构造器内部
  • 类 : XPathParser
  • 作用 : 读取 xml 文件解析为文档对象
  • 构造器
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    //同上步骤创建出document
    this.document = createDocument(new InputSource(inputStream));
  }

4.1 总结:
  • Mapper.xml 已经解析为 Document 对象
  • 接下来准备解析 Document 对象配置到 Configuration对象中

4.2 回到4.1.1.2 parse() 方法
  • 类 : XMLMapperBuilder
  • 方法 : parse()
  • 作用 : 将 Document 对象解析配置到 Configuration 对象中
public void parse() { 
	//确认是否解析过该配置文件
    if (!configuration.isResourceLoaded(resource)) {
      //解析<Mapper>节点内部所有节点到Configuration对象中
      configurationElement(parser.evalNode("/mapper"));
      //将该接口对应的xml添加到已加载资源
      configuration.addLoadedResource(resource);
      //为接口绑定命名空间
      bindMapperForNamespace();
    }

    parsePendingResultMaps();
    parsePendingChacheRefs();
    parsePendingStatements();
  }
4.2.1 configurationElement() 配置Mapper中元素
  • 类 : XMLMapperBuilder
  • 方法 : configurationElement()
  • 作用 : 各个方法都是解析Mapper.xml 的各个节点, 并配置到 configuration 中
private void configurationElement(XNode context) {
    try {
      //获取命名空间
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      //绑定命名空间
      builderAssistant.setCurrentNamespace(namespace);
      //从另一个命名空间引用缓存配置
      cacheRefElement(context.evalNode("cache-ref"));
      //配置缓存标签
      cacheElement(context.evalNode("cache"));
      //参数映射
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      //结果集映射
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      //sql字段映射
      sqlElement(context.evalNodes("/mapper/sql"));
      //CRUD映射
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
  }
  • 各个解析方法总结
4.2.1.1 cacheRefElement ("cache-ref ")
  1. 元素存放容器: 解析完的 cache-ref 放在 cacheRefMap ( HashMap ) 中
  2. 具体存放类 : Configuration对象中
  • Key : mapper 文件的 namespace
  • Value : < cache-ref > 中配置的namespace

4.2.1.2 cacheElement (“cache”)
根据< cache >配置的属性创建一个缓存对象,使用该对象作为 mybatis 缓存

4.2.1.3 parameterMapElement (“parameterMap”)
  1. 元素存放容器: 解析完的ParameterMap放在 parameterMaps (即StrictMap )中
  2. 具体存放类 : Configuration对象中
  • Key : mapper 的 namespace +"."+< parameterMap>标签中的 id 属性
  • Value : ParameterMap对象

4.2.1.4 resultMapElements(“resultMap”)
  1. 元素存放容器: 解析完的ResultMap放在 resultMaps (即StrictMap )中
  2. 具体存放类 : Configuration对象中
  • Key : mapper 的 namespace +"."+< resultMap>标签中的 id 属性
  • Value : ResultMap对象

4.2.1.5 sqlElement(“sql”)
  1. 元素存放容器: 解析完的 ResultMap 放在 resultMaps (即StrictMap )中
  2. 具体存放类 : XMLMapperBuilder对象中
  • Key : mapper 的 namespace +"."+< sql>标签中的 id 属性
  • Value : ResultMap对象

4.2.1.6 buildStatementFromContext(“select|insert|update|delete”)
  1. 元素存放容器: 解析完的 MappedStatement 对象 放在 mappedStatements(即StrictMap )中
  2. 具体存放类 : Configuration对象中
  • Key : mapper的namespace+"."+< select>|< insert>|< update>|< delete>标签中的id属性
  • Value : MappedStatement 对象

4.2 总结
  • 已经将 Mapper.xml 生成的 Document 对象内容配置到 Configuration 对象中
  • 接下来,详细看下解析sql语句生成MappedStatement 对象过程

4.3 buildStatementFromContext() 构建 MappedStatement 对象
  • 类 : XMLMapperBuilder
  • 方法 : buildStatementFromContext("select | insert | update | delete ")
  • 作用 : 从 CURD节点中构建 statement对象
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {	
	//遍历所有CURD节点
    for (XNode context : list) {
      // 创建statement 解析器
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
      try {
        //使用解析器解析节点到statement中
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }
4.3.1 parseStatementNode() 解析CURD节点内属性
  • 类 : XMLStatementBuilder
  • 方法 : buildStatementFromContext("select | insert | update | delete ")
  • 作用 : 从CURD各个节点中解析出各自的属性
public class XMLStatementBuilder extends BaseBuilder {
  //Mapper构建助手
  private MapperBuilderAssistant builderAssistant;
  //解析Mapper后的节点对象
  private XNode context;
  private String requiredDatabaseId;
  
public void parseStatementNode() {
	//获取id属性
    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);

    Class<?> resultTypeClass = resolveClass(resultType);
    String resultSetType = context.getStringAttribute("resultSetType");
    //使用PrepareStatement类型
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);

    String nodeName = context.getNode().getNodeName();
    //获取Sql语句指令类型(insert|delete|update|select)
    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
    XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
    includeParser.applyIncludes(context.getNode());

    // Parse selectKey after includes and remove them.
    processSelectKeyNodes(id, parameterTypeClass, langDriver);
    
    // Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    String resultSets = context.getStringAttribute("resultSets");
    String keyProperty = context.getStringAttribute("keyProperty");
    String keyColumn = context.getStringAttribute("keyColumn");
    KeyGenerator keyGenerator;
    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))
          ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
    }
	//传递参数,使用MappedStatement构建助手构建
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered, 
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }

4.3.2 addMappedStatement() 创建 MappedStatement对象
  • 类 : MapperBuilderAssistant
  • 方法 : addMappedStatement()
  • 作用 : 传递参数,创建对应的MappedStatement 对象
public MappedStatement addMappedStatement(
      String id,
      SqlSource sqlSource,
      StatementType statementType,
      SqlCommandType sqlCommandType,
      Integer fetchSize,
      Integer timeout,
      String parameterMap,
      Class<?> parameterType,
      String resultMap,
      Class<?> resultType,
      ResultSetType resultSetType,
      boolean flushCache,
      boolean useCache,
      boolean resultOrdered,
      KeyGenerator keyGenerator,
      String keyProperty,
      String keyColumn,
      String databaseId,
      LanguageDriver lang,
      String resultSets) {

    if (unresolvedCacheRef) {
      throw new IncompleteElementException("Cache-ref not yet resolved");
    }

    id = applyCurrentNamespace(id, false);
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
    //封装属性,创建出MappedStatement构建器对象
    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
        .resource(resource)
        .fetchSize(fetchSize)
        .timeout(timeout)
        .statementType(statementType)
        .keyGenerator(keyGenerator)
        .keyProperty(keyProperty)
        .keyColumn(keyColumn)
        .databaseId(databaseId)
        .lang(lang)
        .resultOrdered(resultOrdered)
        .resultSets(resultSets)
        .resultMaps(getStatementResultMaps(resultMap, resultType, id))
        .resultSetType(resultSetType)
        .flushCacheRequired(valueOrDefault(flushCache, !isSelect))
        .useCache(valueOrDefault(useCache, isSelect))
        .cache(currentCache);
	//封装参数集合
    ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
    if (statementParameterMap != null) {
      statementBuilder.parameterMap(statementParameterMap);
    }
	//构建出MappedStaement对象
    MappedStatement statement = statementBuilder.build();
    //将创建好的MappedStatement对象,封装到Configuration对象的mappedStatements集合属性中
    configuration.addMappedStatement(statement);
    return statement;
  }
4.3 总结
  • 4.3 过程完成了 MappedStatement 对象创建并存放在 Configuration 对象中
总结
读取mybatis-config.xml 配置文件时,会将该配置文件配置属性封装到configuration对象中, 并且将Mapper.xml 中sql 解析为一个个MappedStatement 对象,放入configuration对象中 ,实际就是将mybatis 的所有配置文件解析封装到 configuration 对象内部
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值