`

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

阅读更多

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  
讲解的很不错,学习了

相关推荐

    深入理解Spring与Dubbo整合原理与源码分析:从启动类配置到注解解析.rar

    《深入理解Spring与Dubbo整合原理与源码分析:从启动类配置到注解解析》是一本专注于探讨Spring和Dubbo两大开源框架整合的技术书籍。本文将基于书中的主题,结合标签“spring”、“dubbo”和“软件/插件”,深入解析...

    X86平台上Linux的低级初始化过程分析.pdf

    10. **初始化文件系统**:挂载根文件系统,这是系统运行所必需的,用于存储系统程序和配置文件。 11. **启动系统服务**:启动内核模块和服务,如网络协议栈、系统日志等。 12. **过渡到用户空间**:最后,通过启动...

    tomcat启动原理解析

    - Tomcat会读取`conf/catalina.properties`、`conf/server.properties`等配置文件,获取服务器的默认设置。 - `webapps`目录下的每个应用都有对应的`WEB-INF/web.xml`,定义了应用的部署信息,Tomcat会逐一解析...

    XML文件解析源码

    XML(eXtensible Markup Language)文件是一种结构化数据存储格式,广泛应用于Web服务、配置文件、数据交换和文档存储等领域。它允许自定义标签来描述数据内容,使得数据具有可读性和易于处理的特性。在本文中,我们...

    sax解析xml文件

    - 一个主程序,用于初始化SAX解析器并设置自定义的`ContentHandler`。 - 可能还有一个XML文件作为输入,供解析器读取。 使用SAX解析XML的优点在于效率高,适用于处理大型XML文件。但缺点是需要编写更多代码来处理...

    Wireshark学习笔记

    4. 读取配置文件:包括读取capture filter和display filter文件,分别保存在capture_filter和display_filter全局变量中。 5. 读取disabled protocols文件:保存全局变量global_disabled_protos和disabled_protos中。...

    Spring 源码分析(Bean的初始化)

    在Spring框架中,Bean的初始化是一个至关重要的过程,它涉及到从XML配置文件或者注解中读取Bean的定义,解析并构建Bean实例。本篇文章主要分析了Spring如何通过`ClassPathXmlApplicationContext`来启动和初始化Bean...

    程序的配置文件_底层_源码

    源码层面,配置文件的读取通常在程序初始化阶段进行,通过专门的配置模块加载并解析。开发者需要关注配置文件加载的错误处理,确保即使配置文件出现问题,程序也能以某种降级模式正常运行。此外,源码中应有良好的...

    STM32F1XX代码工程::sd卡读写(库函数).rar_DSP 文件读取_dsp sd_stm32f10x sd_stm32

    例如,可能有`stm32f1xx_hal_conf.h`配置文件,它定义了外设时钟设置和其他硬件配置;`stm32f1xx_hal_sd.h`和`stm32f1xx_hal_sd.c`包含SD卡的HAL(Hardware Abstraction Layer,硬件抽象层)驱动,提供了易于使用的...

    利用缓存机制快速读取XML文件数据

    1. **初始化缓存**:首次读取XML文件时,将其完全解析并存储在内存中。 2. **文件状态监测**:记录XML文件最后修改的时间戳。 3. **数据读取**: - 如果请求数据且文件未被修改,则直接从缓存中获取。 - 如果文件...

    18 Spring IoC容器如何读取应用外部的xml,txt,图形或者属性文件?慕课专栏(1)1

    这个过程涉及多个步骤,包括解析XML文件,创建Bean定义,以及实例化和初始化Bean。`AbstractBeanDefinitionReader`类是用于读取和解析XML文件的关键组件,它负责将XML配置转换为Spring可以理解的Bean定义。 值得...

    servlet工作原理解析

    - **init()方法**:这是一个可选步骤,开发者可以根据需要重写`init()`方法来完成必要的初始化工作,比如读取配置文件、设置环境变量等。 - **初始化参数**:通过部署描述符(web.xml)可以为Servlet提供初始化...

    xml解析器的源代码

    XML(eXtensible Markup Language)是一种用于标记数据的语言,广泛应用在互联网上,特别是在数据交换、配置文件和文档存储等领域。XML的结构清晰,易于人类阅读,并且机器也能方便地解析和生成。本资源提供了XML...

    STM32H743 读取CPU温度源码

    源码通常会包含初始化、读取、转换和校准的函数,你可以逐一分析理解其工作原理。 此外,由于STM32H743的运行温度较高,为了降低温度,可以采取以下措施: 1. 降低系统时钟频率:减小CPU的工作负荷,减少热量产生...

    matlab从串口读取数据

    以下是一份详细的MATLAB串口读取数据的知识点解析: 1. **初始化串口**: - 首先,我们需要使用`comport`函数来获取可用的串口列表。例如,`comports()`会列出所有可用的串口。 - 选择一个串口,如COM1,然后使用...

    Java Spring 源码解析 Xmind 思维导图

    源码解析中,会详细讲解Bean的定义方式,如XML配置、注解驱动和Java配置类,以及Bean的生命周期,包括初始化方法、后处理器、销毁方法等。 其次,时序图是理解系统间交互的重要工具。在Spring源码解析中,时序图...

    wpa_supplicant代码流程

    通过对`wpa_supplicant`代码流程的详细分析,我们可以了解到这款工具是如何逐步初始化并为无线网络提供认证和密钥管理服务的。从操作系统环境的初始化、认证方法的注册、全局参数的配置,到驱动程序的选择与初始化、...

    c# 串口读取ic卡卡号值

    这个过程通常涉及到与读卡器的协议交互,可能包括初始化、选择卡、请求响应等步骤。具体命令会根据所使用的IC卡类型和读卡器型号有所不同,可能需要查阅相关的读卡器说明书或API文档。 读取IC卡卡号值的过程通常是...

    对用户操作进行纪录,并写入日志

    4. **配置文件读取**:从外部配置文件读取日志文件的路径等信息,增强程序的灵活性和可维护性。 5. **资源管理**:正确地关闭和释放使用的资源,避免内存泄漏。 #### 核心方法解析 1. **构造函数与初始化**: `...

Global site tag (gtag.js) - Google Analytics