java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Mybatis初始化

Mybatis源码解析之初始化分析

作者:二狗家有矿

这篇文章主要介绍了Mybatis源码解析之初始化分析,Mybatis的初始化过程就是mybatis配置文件的解析过程并将解析结果保存到Configuration类。,需要的朋友可以参考下

一、 Mybatis配置文件

configuation是mybatis配置文件的根节点。

configuration 配置
	-properties 属性
	-settings 设置
	-typeAliases 类型别名
	-typeHandlers 类型处理器
	-objectFactory 对象工厂
	-plugins 插件
	-environments 环境
		-environment 环境变量
			-transactionManager 事务管理器
			-dataSource 数据源
			-databaseIdProvider 数据库厂商标识
	-mappers 映射器

本文主要讲解源码,不对配置文件展开

二、配置文件解析过程

1. 初始化demo

下文代码是mybatis通过解析xml配置文件进行初始化的一个简单demo,后续我们将根据这个demo追踪mybatis源码的处理过程。

InputStream inputStream = Resources.getResourceAsStream("mybatis-coonfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();

Mybatis初始化时序图

2. SqlSessionFactoryBuilder#build(InputStream, String. Properties)

SqlSessionFactoryBuilder的build(inputStream)方法通过调用同名的重载方法SqlSessionFactoryBuilder#build(InputStream, String. Properties)来生成需要的SqlSessionFacotry。

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
   try {
     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.
     }
   }
 }
   
 public SqlSessionFactory build(Configuration config) {
   return new DefaultSqlSessionFactory(config);
 }

首先,通过XmlConfigBuilder解析配置文件,并得到configuration类对象。 然后根据configuration作为参数调用build得到所需的SqlSessionFactory,可以看到最终得到的SqlSessionFactory类型是DefaultSqlSessionFactory。

3. XMLConfigBuilder#parse()

public Configuration parse() {
   if (parsed) {
     throw new BuilderException("Each XMLConfigBuilder can only be used once.");
   }
   parsed = true;
   parseConfiguration(parser.evalNode("/configuration"));
   return configuration;
 }
 
 private void parseConfiguration(XNode root) {
   try {
     //issue #117 read properties first
     propertiesElement(root.evalNode("properties"));
     Properties settings = settingsAsProperties(root.evalNode("settings"));
     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);
   }
 }

可以看到,XMLConfigBuilder对xml配置文件中对configuration的子节点进行逐个解析。 以typeAliases为例,遍历typeAliases的子节点,根据配置情况将其加入到configuration对象中对应的typeAliasRegistry属性,其它节点的解析也类似。

private void typeAliasesElement(XNode parent) {
   if (parent != null) {
     for (XNode child : parent.getChildren()) {
       if ("package".equals(child.getName())) {
         String typeAliasPackage = child.getStringAttribute("name");
         configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
       } else {
         String alias = child.getStringAttribute("alias");
         String type = child.getStringAttribute("type");
         try {
           Class<?> clazz = Resources.classForName(type);
           if (alias == null) {
             typeAliasRegistry.registerAlias(clazz);
           } else {
             typeAliasRegistry.registerAlias(alias, clazz);
           }
         } catch (ClassNotFoundException e) {
           throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
         }
       }
     }
   }
 }

4. DefaultSqlSessionFactory#openSession()

@Override
public SqlSession openSession() {
   return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
 }
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  Transaction tx = null;
  try {
    final Environment environment = configuration.getEnvironment();
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    final Executor executor = configuration.newExecutor(tx, execType);
    return new DefaultSqlSession(configuration, executor, autoCommit);
  } catch (Exception e) {
    closeTransaction(tx); // may have fetched a connection so lets call close()
    throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

DefaultSqlSessionFactory#openSession()最终通过DefaultSqlSessionFactory#openSessionFromDataSource(ExecutorType, TransactionLevel, boolean)试下,可以看到最后获得的SqlSession类型是DefaultSqlSession,其中executor类型是SimpleExecutor。

到此这篇关于Mybatis源码解析之初始化分析的文章就介绍到这了,更多相关Mybatis初始化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文