深入MyBatis-运行原理-SqlSessionFactory的初始化

版权声明:转载需声明本人出品 https://blog.csdn.net/weixin_40288381/article/details/88563838

流程图

在这里插入图片描述
SqlSessionFactory初始化流程:

  1. 创建SqlSessionFactoryBuilder对象,调用build方法,生成XmlConfigBuilder
  2. XmlConfigBuilder创建解析器parser
  3. 解析每一个标签把详细信息保存在Configuration中
  4. 解析mapper.xml;Mapper.xml中的每一个元素信息解析出来并保存在全局配置中,将增删查改的每一个标签每一个属性都解析出来,封装成一个MappedStatement–一个MappedStatement就代表一个增删查改标签的详细信息
  5. Configuration返回configuraion给XmlConfigBuilder
  6. XmlConfigBuilder调用build方法,传入configuraion去生成DefaultSqlSession

源码剖析

1.生成SqlSessionFactoryBuilder对象,调用build方法
//生成SqlSessionFactoryBuilder对象
//进入SqlSessionFactoryBuilder对象的build方法
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
2.SqlSessionFactoryBuilder下的build方法下生成XmlConfigBuilder
 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      //XmlConfigBuilder创建解析器parser
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      //parser调用parse方法,返回结果为DefaultSqlSessionFactory(config),即默认SqlSessionFactory实现类为DefaultSqlSessionFactory,并传入后面会配置好的configuration
      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.解析器调用parse方法
 public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    //解析configuration标签,改标签为全局配置文件中的根标签
    parseConfiguration(parser.evalNode("/configuration"));
    //解析完标签信息后,返回已经保存了标签信息的configuraion
    return configuration;
  }
4.解析标签

解析配置文件下每个标签的详细信息并保存在configuraion中

 //传入配置文件根标签
 private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectionFactoryElement(root.evalNode("reflectionFactory"));
      settingsElement(root.evalNode("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);
    }
  }

解析映射文件中标签信息

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 {
          //映射文件需要在全局配置文件下声明,声明路径可以使用resource或者url
          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);
            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);
            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.");
          }
        }
      }
    }
  }

小结

创建SqlSessionFactory的默认实现为DefaultSqlSessionFactory,该方法需要传入Configuration实例。调用SqlSessionFactoryBuilder的build方法会对配置文件中标签进行解析并把详细信息保存在Configuration类,并返回Configuration实例给DefaultSqlSessionFactory,最终生成SqlSessionFactory。

猜你喜欢

转载自blog.csdn.net/weixin_40288381/article/details/88563838