美文网首页
Mybatis源码浅析(二)

Mybatis源码浅析(二)

作者: EnjoyTheLife | 来源:发表于2017-07-01 15:03 被阅读0次

    前言

    上一篇我们通过一个简单的例子了解了基于XML配置文件的方式初始化Mybatis的过程,毫不夸张的说,MyBatis初始化的过程,就是创建 Configuration对象的过程。而在构建SqlSessionFactory的过程中,生成了XMLConfigBuilder实例对象,所以我们就先从XMLConfigBuilder说起。

    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.
    }
    }
    }
    

    XMLConfigBuilder

    首先我们先看下XMLConfigBuilder实例的创建过程,如上述所示,入參为inputStream,environment和properties, 如下所示,是通过生成XPathParser实例后调用私有构造函数来生成的。XPathParser封装了JDK中的Document和XPath对象,其实就是一个工具类,主要用来解析XML文件内容的。

    public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
    }
    
    // 私有构造函数,对应上面代码中的this
    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;
    }
    

    其实分析到这,Mybatis的初始化(其实就是创建Configuration实例的过程)过程就比较清晰了:

    1. 首先创建XMLConfigBuilder 实例,然后创建了 Configuration 实例,顺便把解析XML文件内容的工具类也创建好
    2. 在 XMLConfigBuilder 当中解析 Configuration的每一个节点,并设置到Configuration当中去
    3. 最后返回 Configuration 实例,并以其为入残參,来生成SqlSessionFactory实例
    // 解析 Configuration的每一个节点
    private void parseConfiguration(XNode root) {
    try {
    Properties settings = settingsAsPropertiess(root.evalNode("settings"));
    propertiesElement(root.evalNode("properties"));
    loadCustomVfs(settings);
    typeAliasesElement(root.evalNode("typeAliases"));
    pluginElement(root.evalNode("plugins"));
    objectFactoryElement(root.evalNode("objectFactory"));
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    reflectionFactoryElement(root.evalNode("reflectionFactory"));
    settingsElement(settings);
    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);
    }
    }
    

    BaseBuilder

    XMLConfigBuilder继承了 BaseBuilder,事实上,其他所有解析XML的Builder都继承了这个类。下面是BaseBuilder的大致结构,由此看出,Configuration实例其实是存放在BaseBuilder中的。

    public abstract class BaseBuilder {
    protected final Configuration configuration;
    protected final TypeAliasRegistry typeAliasRegistry;
    protected final TypeHandlerRegistry typeHandlerRegistry;
    
    public BaseBuilder(Configuration configuration) {
    this.configuration = configuration;
    this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
    this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
    }
    ...... // 此处省略了很多方法
    }
    

    下图是BaseBuilder的实现依赖图,你会发现,基本上所有解析XML的类都需要即成这个基类,其中的几个类(Mapper相关的)以后会详细描述。


    __

    XMLConfigBuilder 的具体工作

    上问我们了解到,继承了 BaseBuilder 的 XMLConfigBuilder, 其实是Myabtis初始化的真正入口,那 XMLConfigBuilder 实际上都做了些什么工作呢?其实都在 XMLConfigBuilder 实例的parse方法内。

    // parse方法
    public Configuration parse() {
    if (parsed) {
    throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
    }
    

    从代码上可以看出,其实parse()方法也是抛砖引玉的方法,真正干活的其实是 parseConfiguration 方法

    private void parseConfiguration(XNode root) {
    try {
    Properties settings = settingsAsPropertiess(root.evalNode("settings"));
    //issue #117 read properties first
    propertiesElement(root.evalNode("properties"));
    loadCustomVfs(settings);
    typeAliasesElement(root.evalNode("typeAliases"));
    pluginElement(root.evalNode("plugins"));
    objectFactoryElement(root.evalNode("objectFactory"));
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    reflectionFactoryElement(root.evalNode("reflectionFactory"));
    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);
    }
    }
    

    Mybatis 配置文件之解析详解

    从上面的 parseConfiguration 方法可以看出,Mybatis 配置文件中支持的节点类型包含如下内容,先写到这里,下篇文章依次来了解下每一项的解析过程.

    1. properties 属性
    2. settings 设置
    3. typeAliases 类型命名
    4. plugins 插件
    5. objectFactory 对象工厂
    6. objectWrapperFactory
    7. reflectionFactory
    8. environments 环境
    9. databaseIdProvider 数据库厂商标识
    10. typeHandlers 类型处理器
    11. mappers 映射器

    相关文章

      网友评论

          本文标题:Mybatis源码浅析(二)

          本文链接:https://www.haomeiwen.com/subject/kazwcxtx.html