`

原理分析之三:初始化(配置文件读取和解析)

阅读更多

1. 准备工作

  编写测试代码(具体请参考《Mybatis入门示例》),设置断点,Debug模式运行,具体代码如下: 

String resource = "mybatis.cfg.xml";

Reader reader = Resources.getResourceAsReader(resource);

SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);

SqlSession session = ssf.openSession();

 

2.源码分析

我们此次就对上面的代码进行跟踪和分析,let's go。

首先我们按照顺序先看看第一行和第二行代码,看看它主要完成什么事情:

String resource = "mybatis.cfg.xml";

Reader reader = Resources.getResourceAsReader(resource);

 

读取Mybaits的主配置配置文件,并返回该文件的输入流,我们知道Mybatis所有的SQL语句都写在XML配置文件里面,所以第一步就需要读取这些XML配置文件,这个不难理解,关键是读取文件后怎么存放。

 

我们接着看第三行代码(如下),该代码主要是读取配置文件流并将这些配置信息存放到Configuration类中。

SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);

 

 

SqlSessionFactoryBuilderbuild的方法如下:

public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }

 

其实是调用该类的另一个build方法来执行的,具体代码如下:

public SqlSessionFactory build(Reader reader, String environment, Properties properties) {

    try {

      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);

      return build(parser.parse());

    } catch (Exception e) {

      throw ExceptionFactory.wrapException("Error building SqlSession.", e);

    } finally {

      ErrorContext.instance().reset();

      try {

        reader.close();

      } catch (IOException e) {

        // Intentionally ignore. Prefer previous error.

      }

    }

  }

 

我们重点看一下里面两行:

//创建一个配置文件流的解析对象XMLConfigBuilder,其实这里是将环境和配置文件流赋予解析类
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);

// 解析类对配置文件进行解析并将解析的内容存放到Configuration对象中,并返回SqlSessionFactory
return build(parser.parse());

 

这里的XMLConfigBuilder初始化其实调用的代码如下: 

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());

    ErrorContext.instance().resource("SQL Mapper Configuration");

    this.configuration.setVariables(props);

    this.parsed = false;

    this.environment = environment;

    this.parser = parser; 

  }

 

 

 XMLConfigBuilderparse方法执行代码如下:  

public Configuration parse() {

    if (parsed) {

      throw new BuilderException("Each MapperConfigParser can only be used once.");

    }

    parsed = true;

    parseConfiguration(parser.evalNode("/configuration"));

    return configuration;

  }

 

解析的内容主要是在parseConfiguration方法中,它主要完成的工作是读取配置文件的各个节点,然后将这些数据映射到内存配置对象Configuration,我们看一下parseConfiguration方法内容: 

private void parseConfiguration(XNode root) {

    try {

      typeAliasesElement(root.evalNode("typeAliases"));

      pluginElement(root.evalNode("plugins"));

      objectFactoryElement(root.evalNode("objectFactory"));

      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));

      propertiesElement(root.evalNode("properties"));

      settingsElement(root.evalNode("settings"));

      environmentsElement(root.evalNode("environments"));

      typeHandlerElement(root.evalNode("typeHandlers"));

      mapperElement(root.evalNode("mappers"));

    } catch (Exception e) {

      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);

    }

  }

 

 

最后的build方法其实是传入配置对象进去,创建DefaultSqlSessionFactory实例出来. DefaultSqlSessionFactorySqlSessionFactory的默认实现. 
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

   

 最后我们看一下第四行代码: 

SqlSession session = ssf.openSession();

 

通过调用DefaultSqlSessionFactoryopenSession方法返回一个SqlSession实例,我们看一下具体是怎么得到一个SqlSession实例的。首先调用openSessionFromDataSource方法。  

public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

 

 下面我们看一下openSessionFromDataSource方法的逻辑:  

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Connection connection = null;

try {

//获取配置信息里面的环境信息,这些环境信息都是包括使用哪种数据库,连接数据库的信息,事务
final Environment environment = configuration.getEnvironment();

//根据环境信息关于数据库的配置获取数据源
final DataSource dataSource = getDataSourceFromEnvironment(environment);

//根据环境信息关于事务的配置获取事务工厂
TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);

      connection = dataSource.getConnection();

      if (level != null) {

        //设置连接的事务隔离级别
      connection.setTransactionIsolation(level.getLevel());
      }

      //对connection进行包装,使连接具备日志功能,这里用的是代理。
      connection = wrapConnection(connection);

      //从事务工厂获取一个事务实例
      Transaction tx = transactionFactory.newTransaction(connection, autoCommit);

      //从配置信息中获取一个执行器实例
      Executor executor = configuration.newExecutor(tx, execType);

      //返回SqlSession的一个默认实例
      return new DefaultSqlSession(configuration, executor, autoCommit);

    } catch (Exception e) {

      closeConnection(connection);

      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);

    } finally {

      ErrorContext.instance().reset();

    }

  }

 

传入参数说明:

1ExecutorType:执行类型,ExecutorType主要有三种类型:SIMPLE, REUSE, BATCH,默认是SIMPLE,都在枚举类ExecutorType里面。

2TransactionIsolationLevel:事务隔离级别,都在枚举类TransactionIsolationLevel中定义

3autoCommit:是否自动提交,主要是事务提交的设置。

 

 DefaultSqlSessionSqlSession的实现类,该类主要提供操作数据库的方法给开发人员使用。

 

这里总结一下上面的过程,总共由三个步骤:

步骤一:读取Ibatis的主配置文件,并将文件读成文件流形式(InputStream)

 

步骤二:从主配置文件流中读取文件的各个节点信息并存放到Configuration对象中。读取mappers节点的引用文件,并将这些文件的各个节点信息存放到Configuration对象。

 

步骤三:根据Configuration对象的信息获取数据库连接,并设置连接的事务隔离级别等信息,将经过包装数据库连接对象SqlSession接口返回,DefaultSqlSessionSqlSession的实现类,所以这里返回的是DefaultSqlSessionSqlSession接口里面就是对外提供的各种数据库操作。

24
1
分享到:
评论
7 楼 lgh1992314 2017-10-20  
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 指定properties配置文件, 我这里面配置的是数据库相关 -->
    <properties resource="jdbc.properties"/>

    <!--<settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>-->

    <typeAliases>
        <typeAlias type="com.xiya.entity.Person" alias="Person"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <!-- 事务管理类型,JDBC表示直接使用JDBC的提交和回滚设置,依赖于数据源得到的连接来管理事务 -->
            <transactionManager type="JDBC"/>
            <!-- 数据库连接池POOLED表示使用数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!-- SQL代码和映射信息配置文件 -->
    <mappers>
        <mapper resource="com/xiya/dao/PersonMapper.xml"/>
        <!--<mapper url="file:/// D:\N3verL4nd/Desktop/MyBatis/src/main/resources/com/xiya/entity/PersonMapper.xml"/>-->
    </mappers>

</configuration>
6 楼 bo_hai 2015-11-01  
mybatis.cfg.xml
文件长什么样,能发出来看看么?
5 楼 hanson08 2015-01-08  
很好,很强大!一直保持高度注意。
4 楼 zy297035937 2014-03-19  
3 楼 bluend1004 2013-08-29  
楼主,您用的是mybatis3.1.1吗?我看的源码跟您的博文有些出入啊?
2 楼 zhangyou1010 2012-12-08  
博主,您好,能麻烦制作一份您博客的电子书吗?谢谢了。
1 楼 zwbill 2012-09-17  
讲解的很不错,学习了

相关推荐

    SSH的jar包.rar

    下面粗略的分析下FilterDispatcher工作流程和原理:FilterDispatcher进行初始化并启用核心doFilter。 Hibernate 的原理 1.通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件 2.由hibernate....

    深入解析Oracle.DBA入门进阶与诊断案例

    针对数据库的启动和关闭、控制文件与数据库初始化、参数及参数文件、数据字典、内存管理、Buffer Cache与Shared Pool原理、重做、回滚与撤销、等待事件、性能诊断与SQL优化等几大Oracle热点主题,本书从基础知识入手...

    JAVA上百实例源码以及开源项目

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    java源码包---java 源码 大量 实例

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    java源码包2

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    java源码包3

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    java源码包4

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个...

    寒江独钓-Windows内核安全编程(高清完整版).part7

    7.9.2 初始化回调、卸载回调和绑定回调 213 7.9.3 绑定与回调 215 7.9.4 插入请求回调 216 7.9.5 如何利用sfilter.lib 218 本章的示例代码 221 练习题 221 第8章 文件系统透明加密 223 8.1 文件透明加密的应用 224 ...

    寒江独钓-Windows内核安全编程(高清完整版).part4

    7.9.2 初始化回调、卸载回调和绑定回调 213 7.9.3 绑定与回调 215 7.9.4 插入请求回调 216 7.9.5 如何利用sfilter.lib 218 本章的示例代码 221 练习题 221 第8章 文件系统透明加密 223 8.1 文件透明加密的应用 224 ...

    JAVA上百实例源码以及开源项目源代码

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    寒江独钓-Windows内核安全编程(高清完整版).part1

    7.9.2 初始化回调、卸载回调和绑定回调 213 7.9.3 绑定与回调 215 7.9.4 插入请求回调 216 7.9.5 如何利用sfilter.lib 218 本章的示例代码 221 练习题 221 第8章 文件系统透明加密 223 8.1 文件透明加密的应用 224 ...

    寒江独钓-Windows内核安全编程(高清完整版).part6

    7.9.2 初始化回调、卸载回调和绑定回调 213 7.9.3 绑定与回调 215 7.9.4 插入请求回调 216 7.9.5 如何利用sfilter.lib 218 本章的示例代码 221 练习题 221 第8章 文件系统透明加密 223 8.1 文件透明加密的应用 224 ...

    寒江独钓-Windows内核安全编程(高清完整版).part5

    7.9.2 初始化回调、卸载回调和绑定回调 213 7.9.3 绑定与回调 215 7.9.4 插入请求回调 216 7.9.5 如何利用sfilter.lib 218 本章的示例代码 221 练习题 221 第8章 文件系统透明加密 223 8.1 文件透明加密的应用 224 ...

    寒江独钓-Windows内核安全编程(高清完整版).part3

    7.9.2 初始化回调、卸载回调和绑定回调 213 7.9.3 绑定与回调 215 7.9.4 插入请求回调 216 7.9.5 如何利用sfilter.lib 218 本章的示例代码 221 练习题 221 第8章 文件系统透明加密 223 8.1 文件透明加密的应用 224 ...

    寒江独钓-Windows内核安全编程(高清完整版).part2

    7.9.2 初始化回调、卸载回调和绑定回调 213 7.9.3 绑定与回调 215 7.9.4 插入请求回调 216 7.9.5 如何利用sfilter.lib 218 本章的示例代码 221 练习题 221 第8章 文件系统透明加密 223 8.1 文件透明加密的应用 224 ...

    Windows内核安全与驱动开发光盘源码

    9.4.5 用户配置的初始化 149 9.4.6 链接给应用程序 151 9.4.7 小结 152 9.5 FAT12/16磁盘卷初始化 152 9.5.1 磁盘卷结构简介 152 9.5.2 Ramdisk对磁盘的初始化 154 9.6 驱动中的请求处理 160 9.6.1 请求的...

    Windows内核安全驱动开发(随书光盘)

    9.4.5 用户配置的初始化 149 9.4.6 链接给应用程序 151 9.4.7 小结 152 9.5 FAT12/16磁盘卷初始化 152 9.5.1 磁盘卷结构简介 152 9.5.2 Ramdisk对磁盘的初始化 154 9.6 驱动中的请求处理 160 9.6.1 请求的...

Global site tag (gtag.js) - Google Analytics