MyBatis(技术NeiMu):核心处理层(MyBatis的初始化)

本文详细解读MyBatis配置文件解析过程,通过BaseBuilder与XMLConfigBuilder展示如何利用建造者模式逐步初始化SqlSessionFactory,涉及配置文件结构、标签解析和自定义组件的整合。

回顾

前面已经将基础支持层看完了,各种底层模块的功能

  • 类型转换
  • 参数解析器
  • 数据库连接池
  • 事务
  • 缓存

核心处理层

下面开始学习核心处理层

首先,核心处理层包括6个部分

  1. 配置解析
  2. 参数映射
  3. SQL解析
  4. SQL执行
  5. 结果集映射
  6. 插件

MyBatis初始化

首先先看第一个部分,配置解析,MyBatis跟Spring一样,MyBatis也有配置文件,因此也需要去解析配置文件,而在MyBatis中的配置文件主要有两个,分别是mybatis-config.xml和映射配置文件

建造者模式

建造者模式是用来将一类复杂对象的构建过程与它的表示分离,让相同的建造工程可以有不同的表示,比如A产品和B产品的建造流程是一样的,那么A产品和B产品就可以使用同一套建造流程!这时候就是使用相同的构建过程,但表示的产品不一致了

首先建造者模式需要三个对象

  • 建造者(接口):负责使用特定建造顺序去建造产品!
  • 导演:调用具体的建造者去创建产品,为建造者提供数据来源!
  • 产品

建造者模式的优点

  • 使用导演来构建出具体的产品,但构建的细节在建造者,所以导演根本不知道创建产品的具体细节,只负责构建所需的信息传递,实现了产品对象的上层代码和产品对象的解耦,最上层的指挥完全不知道产品的建造流程,我们不需要改动指挥的代码!!!
  • 建造者模式将复杂的产品的创建过程分散到了不同的构造步骤中,这样可以对产品创建过程实现更加精细的控制,同时让创建过程更加清晰,建造者将复杂产品的创建过程分开多个方法来创建,并且使用一个build方法来规定了先执行哪个方法,说白了就是先创建哪个部位
  • 每个具体的构造者有产品的每个部位的创建方法,因此一个具体的构建者是可以单独创建出完整的产品对象的,而具体的建造者之间是独立的,因此当我们新增产品时,去新添加建造者即可!然后指挥调用新的建造者来build即可!

构造者模式的缺点

  • 创建的产品要有共同点,组成部分相似,并且创建的流程要基本一致,如果产品很多、产品内部变化复杂、产品之间的差异性很大,是不适合使用建造者模式的,因为产品很多且内部变化复杂会导致建造者越来越多,而产品之间的差异性很大,也会导致建造者越来越多。。。。。。

初始化!BaseBuilder!

在MyBatis中,初始化过程就采用了建造者模式,说白了创建SqlSessionFactory的时候采用了建造者模式,具体的产品是SqlSessionFactory,指挥者是SqlSessionFactoryBuilder,那谁是建造者呢?看代码!

指挥者SqlSessionFactoryBuilder会调用build方法来调用建造者来进行创建SqlSessionFactory(产品),源码如下

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
   
   
    try {
   
   
        //建造者就是XMLConfigBuilder
        //而且注意,这里建造者建造的并不是直接的SqlSessionFactory
       	//创建出需要的建造者
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        //build方法就是指挥者去调用建造者去创建产品了!
      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.
      }
    }
  }

可以看到,对于SqlSessionFactory这个产品的建造者就是XMLConfigBuilder对象,可能因为这个产品只有一款,所以这里没有使用接口

下面就来看一下MyBatis的建造者系列(XmlConfigBuilder是继承了BaseBuilder的,因此从BaseBuilder开始看起)

在这里插入图片描述
BaseBuilder其实就扮演着建造者接口的角,虽然其是一个抽象类,所有的具体建造者都是在其基础上建立的

三个关键成员属性

  • configuration:存储MyBatis的所有配置信息的
  • typeAliasRegistry:之前我们也看过了,这是类型别名注册中心(对Java类型取别名,比如java.lang.Integer转化为int)
  • typeHandlerRegistry:类型转换器注册中心(TypeHandler,用来将数据库类型转化为Java类型的)

而且从构造方法上可以看到,typeAliasRegistry和typeHandlerRegistry都是从Configuration来的,也就是从配置文件上来的!!!

在这里插入图片描述
现在BaseBuilder先看到这

XMLConfigBuilder

回到我们的XMLConfigBuilder,SqlSessionFactoryBuilder就是指挥XMLConfigBuilder来进行,先来看一下XMLConfigBuilder的结构

在这里插入图片描述
关键的属性

  • parsed:代表是否已经解析过mybatis-config.xml配置文件了(用改标志来让配置文件只被解析一次!!!)
  • XPathParser:用来解析mybatis-config.xml配置文件的XPathParser对象,前面已经看过了,其底层是解析DOM树的
  • environment:environment标签的default属性
  • ReflectorFactory:负责创建和缓存Reflector对象的,Reflector就是用来将行记录映射成Java Bean的

在这里插入图片描述
可以看到执行的是build方法,而在build方法之前先会执行构造者的parse方法,下面就来看看这个构造者如何创建产品的

源码如下

public Configuration parse() {
   
   
    //判断MyBatis文件是否已经解析过了
    if (parsed) {
   
   
        //如果已经解析过,抛错
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    //没有解析过,将标志位改为true,开始解析
    parsed = true;
    //在mybatis配置文件中找到configuration节点,并开始进行解析
    //之前已经分析过XPathParser的evalNode方法了,就是解析该标签节点
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
  1. 判断是不是已经解析过了,如果解析过了,抛错
  2. 如果没有解析过,修改标志位,代表现在进行解析
  3. 使用XPathParser取解析configuration标签节点后,调用parseConfiguration去处理解析结果
parseConfiguration

该方法就是用来正式解析MyBatis总配置文件下有用的信息了,也就是configuration标签节点下的信息

在这里插入图片描述
该方法源码如下,可以看到,这就是parseConfiguration方法就是建造者的建造流程了!说得更具体一点是解析配置文件,然后按照建造流程去取配置文件里面的对应节点信息来创建Configuration的流程!!!

private void parseConfiguration(XNode root) {
   
   
  try {
   
   
    //解析configuration标签下的properties属性,组装Configuration的properties部分
    propertiesElement(root.evalNode("properties"));
    //获取configuration标签下的settings属性
    Properties settings = settingsAsProperties(root.evalNode("settings"));
    //从settings部分去设置vfsImpl字段(虚拟文件系统,之前提到过这个用来查找文件的!!)
    loadCustomVfs(settings);
    loadCustomLogImpl(settings);
    //解析typeAliases标签,并组装Configuration的typeAliases部分
    typeAliasesElement(root.evalNode("typeAliases"));
    //解析plugins标签,并组装Configuration的plugins部分
    pluginElement(root.evalNode("plugins"));
    //解析objectFatory标签,并组装Configuration的objectFactory部分
    objectFactoryElement(root.evalNode("objectFactory"));
    //解析objectWrapperFactory标签,并组装Configuration的objectWrapperFactory部分
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    //解析reflectorFactory标签,并组装Configuration的reflectorFactory部分
    reflectorFactoryElement(root.evalNode("reflectorFactory"));
     //将上面解析出的settings属性,组装Configuration的setting部分
    settingsElement(settings);
    //解析environments属性,组装Configuration的environments部分
    environmentsElement(root.evalNode("environments"));
    //解析databseIdProvider属性,组装Configuration的databaseIdProvider部分
    databaseIdProviderElement(root.evalNode("databaseIdProvider"));
     //解析typeHandlers属性,组装Configuration的typeHandlers部分
    typeHandlerElement(root.evalNode("typeHandlers"));
      //解析mappers属性,组装Configuration的mappers部分
    mapperElement(root.evalNode("mappers"));
  } catch (Exception e) {
   
   
    throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
  }
}

可以看到,其实XMLConfigBuilder建造的产品其实是Configuration,也就是解析出来的配置文件里面的内容,并且按照一定的顺序来解析配置文件里面的标签,然后进行组装到Configuration中,最后完成创建,也就是说对于Configuration这个产品来说已经被分成几部分来完成创建了,解析组装的顺序如下

  • properties标签
  • typeAlias标签
  • plugins标签
  • objectFactory标签
  • objectFactoryWrapper标签
  • settings标签
  • environments标签
  • databaseIdProvider标签
  • typeHandler标签
  • mapper标签

下面就看一下,MyBatis是如何对这几个标签节点进行解析的

解析Properties标签

对应的方法为propertiesElement,源码如下

先说明一下properties标签的作用,该标签的子标签其实就是用来记录一些配置信息的,比如数据库的连接信息,账号密码。。。。。。。

private void propertiesElement(XNode context
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值