Mybatis(二) - Mybatis是如何创建出SqlSessionFactory的

Mybatis 如何创建出SqlSessionFactory

本篇文章是通过看视频学习总结的内容, 如有错误的地方请谅解,并联系博主及时修改,谢谢您的阅读.

源码地址: mybatis 中文注释版

从上一篇延申到本篇博客 《Mybatis(一) - Mybatis 最原始是使用方式》

  • 1 从Junit 测试类进入Mybatis 源码中
@Before
public void prepare() throws IOException {
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    // 进入 build 方法
    sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
  • 2 进入 build 方法, 这里不难看出 XMLConfigBuilder使用来解析mybatis-config.xml文件的
// 进入到 build 方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      // 用于解析 mybatis-config.xml,同时创建了 Configuration 对象 
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // 解析XML,最终返回一个 DefaultSqlSessionFactory 
      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 进入到 XMLConfigBuilder 类中,手动创建了Configuration对象,这个对象好像很熟悉,不就是 mybatis-config.xml 的root节点吗

// 进入到 XMLConfigBuilder 类中,
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
	// 手动new出了 Configuration 对象,	
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }
  • 4 那么我们继续进入到 org.apache.ibatis.session.Configuration 对象中,一探究竟,在这里我只放了一部成员变量的代码,在这里面会发现,定义了很多变量,例如 cacheEnabled=true 打开二级缓存的标志,原来Mybatis 在这里设置了默认值。因为在XMLConfigBuilder 类中,调用了 Configuration 对象的无参构造器,那么无参构造器中究竟干了什么事情。
public class Configuration implements Serializable {
	 protected Environment environment;
	
	 protected boolean safeRowBoundsEnabled;
	 protected boolean safeResultHandlerEnabled = true;
	 protected boolean mapUnderscoreToCamelCase;
	 protected boolean aggressiveLazyLoading;
	 protected boolean multipleResultSetsEnabled = true;
	 protected boolean useGeneratedKeys;
	 protected boolean useColumnLabel = true;
	 protected boolean cacheEnabled = true;
	 protected boolean callSettersOnNulls;
	 protected boolean useActualParamName = true;
	 protected boolean returnInstanceForEmptyRow;
	....
}
  • 5 Configuration 无参构造器,全局的设置了类的别名,例如 LruCache.class 全局上下问中就可以使用 LRU来表示淘汰机制的缓存实现
public Configuration() {
    // 为类型注册别名
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

    typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
    typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
    typeAliasRegistry.registerAlias("LRU", LruCache.class);
    typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
    typeAliasRegistry.registerAlias("WEAK", WeakCache.class);

    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);

    typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
    typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

    typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
    typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
    typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
    typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
    typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
    typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
    typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

    typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
    typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);

    languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
    languageRegistry.register(RawLanguageDriver.class);
  }
  • 6 紧接着回到 SqlSessionFactory 类的 build方法中, 找到 build(parser.parse()); 进入 parser.parse() 中,可以很明确的发现,这里开始正式解析 xml文件到 Configuration 对象中,里面包含了对 mapper.xml 文件、自定义类的别名、插件、数据源…等等解析
public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
	// 拿到 root(configuration) 节点 
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

// 解析root节点下所有节点
private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      // 对于全局配置文件各种标签的解析
      propertiesElement(root.evalNode("properties"));
      // 解析 settings 标签
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      // 类型别名
      typeAliasesElement(root.evalNode("typeAliases"));
      // 插件
      pluginElement(root.evalNode("plugins"));
      // 用于创建对象
      objectFactoryElement(root.evalNode("objectFactory"));
      // 用于对对象进行加工
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      // 反射工具箱
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      // settings 子标签赋值,默认值就是在这里提供的 >>
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      // 创建了数据源 >>
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      // 解析引用的Mapper映射器
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
  • 7 上一步是 找到 build(parser.parse()); 进入 parser.parse() 中,而这一步则是进入 build() 方法中,看看Mybatis是怎么创建 SqlSessionFactory 出来的,我靠,居然是直接new 出一个默认的SqlSessionFactory
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

由此可见,Mybatis 在初始化的时候,完成sql与statementId映射关系,也包含POJO的与Class的映射关系,总而言之,在Configuration初始化完毕后所有的初始化动作将完毕。主要初始化动作是在org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration()方法中。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值