Mybatis源码学习(一)SqlSessionFactory_枫叶之声的博客-程序员宅基地

技术标签: java  Mybatis源码  数据库  sql  

1.使用JAVA API 方式构建

JAVA API初始化的方式虽然不常用,但是相较于XML的方式可以更清楚的看到Configuration的构成,其示例如下:

PooledDataSource dataSource = new PooledDataSource();
dataSource.setDriver("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT");
dataSource.setUsername("root");
dataSource.setPassword("root");
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(UmsMemberMapper.class);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

2.使用XML方式构建

2.1.获取InputStream

        【代码2-1】

InputStream inputStream = null;
try {
    inputStream =  Resources.getResourceAsStream("/mybatis-config.xml");
} catch (IOException e) {
    e.printStackTrace();
}

在代码2-1中将配置文件的路径传递给了Resource中的getResourceAsStream方法。我们下面来看看getResourceAsStream方法的详情

【代码2-2】org.apache.ibatis.io.Resources

public static InputStream getResourceAsStream(String resource) throws IOException {
    return getResourceAsStream((ClassLoader)null, resource);
}
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
    if (in == null) {
        throw new IOException("Could not find resource " + resource);
    } else {
        return in;
    }
}

代码【2-3】org.apache.ibatis.io.ClassLoaderWrapper

public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
    return this.getResourceAsStream(resource, this.getClassLoaders(classLoader));
}
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
    ClassLoader[] var3 = classLoader;
    int var4 = classLoader.length;

    for(int var5 = 0; var5 < var4; ++var5) {
        ClassLoader cl = var3[var5];
        if (null != cl) {
            InputStream returnValue = cl.getResourceAsStream(resource);
            if (null == returnValue) {
                returnValue = cl.getResourceAsStream("/" + resource);
            }

            if (null != returnValue) {
                return returnValue;
            }
        }
    }

    return null;
}

        代码2-2的 getResourceAsStream方法都在org.apache.ibatis.io中的Resource类中,代码2-1中的代码调用了Resource类中的getResourceAsStream方法,Resource类中的getResourceAsStream方法最终调用了ClassLoaderWrapper的getResourceAsStream(String resource, ClassLoader[] classLoader),根据 配置文件的路径获取到配置文件的输入流。代码2-3给出了该方法的源码。

          代码2-3的getResourceAsStream方法会依次调用传入的每一个类加载器的getResourceAsStream方法来尝试获取配置文件的输入流。在尝试过程中如果失败的话,会在传入的地址前加入"/" 再试一次,只要尝试成功,即表明成功加载了指定的资源,会将所获得的输入流返回。

        整个过程中涉及的Resource类和ClassLoadWrapper均在Mybatis的io包中,这也印证了Resource类和ClassLoaderWrapper类是负责读写外部文件的。

补充说明:类加载器具有读取外部资源的能力,所以这里要借助的是类加载器的这种能力

2.2.配置信息读取

读取inputStream之后,然后进行的代码2-4的操作

【代码2-4】

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

代码2-4首先构造了一个SqlSessionFactoryBuilder对象,然后调用SqlSessionFactoryBuilder对象的build。然后返回SqlSessionFactory对象,build方法是有多个的,其中的核心代码如代码2-5所示

【代码2-5】

public SqlSessionFactory build(InputStream inputStream) {
    return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    SqlSessionFactory var5;
    try {
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        var5 = this.build(parser.parse());
    } catch (Exception var14) {
        throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
    } finally {
        ErrorContext.instance().reset();

        try {
            inputStream.close();
        } catch (IOException var13) {
        }

    }

    return var5;
}

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

build(InputStream inputStream, String environment, Properties properties)方法最核心的部分如代码2-6所示

【代码2-6】

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());

这两行代码进行了三步操作

1.生成了一个XMLConfigBuilder对象

2.调用XMLConfigBuilder对象的parse方法,得到一个Configuration对象(因为parse方法的返回值是Configuration对象)

3.调用了SqlSessionFactoryBuilder的build方法,传入参数为Configuration对象

我们对上述三步进行追踪,首先找到XMLConfigBuilder类的parse方法,如代码2-7所示

【代码2-7】

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

代码2-7核心部分为 this.parseConfiguration(this.parser.evalNode("/configuration"));,因为configuration节点是mybatis配置文件的根节点,因此这里是解析整个配置文件的入口。而parseConfiguration是解析配置文件的入口,parseConfiguration方法的详情如代码【2-8】所示

【代码2-8】

private void parseConfiguration(XNode root) {
    try {
        this.propertiesElement(root.evalNode("properties"));
        Properties settings = this.settingsAsProperties(root.evalNode("settings"));
        this.loadCustomVfs(settings);
        this.loadCustomLogImpl(settings);
        this.typeAliasesElement(root.evalNode("typeAliases"));
        this.pluginElement(root.evalNode("plugins"));
        this.objectFactoryElement(root.evalNode("objectFactory"));
        this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
        this.settingsElement(settings);
        this.environmentsElement(root.evalNode("environments"));
        this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        this.typeHandlerElement(root.evalNode("typeHandlers"));
        this.mapperElement(root.evalNode("mappers"));
    } catch (Exception var3) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
    }
}

在代码 2-8中,parseConfiguration方法依次解析了配置文件的configuration下的一级节点,各个子方法,每个子方法对应的是每一个一级节点,解析出来的信息都放到Configuration实例中。Configuration对象保存配置文件的所有设置信息,也保存映射文件的信息。

2.3 构造SqlSessionFactory

生成Configuration象之对后,之后进行的是代码2-9的操作

【代码2-9】

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

        代码2-9返回的DefaultSqlSessionFactory对象,SqlSessionFactory是一个接口, DefaultSqlSessionFactory是实现SqlSessionFactory接口的实现类。

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 这一句解析就结束了,

总结

        通过上面的分析,Mybatis的初始化阶段已经分析完毕,在初始化阶段,Mybatis主要进行了以下几项工作:

        1.根据配置文件的位置,获取它的输入流InputStream。

        2.从配置文件的根节点开始,逐层解析配置文件,解析过程中不断把解析结果放进Configuration对象

        3.以配置好的Configuration对象为参数,获取一个SqlsessionFactory对象

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_39024790/article/details/121199974

智能推荐

(十) 线段树_jssd的博客-程序员宅基地_js线段树

线段树也被称作区间树(Segment Tree)为什么使用线段树一类问题对于有一类问题, 我们关心的时线段(或者区间)经典的线段树问题: 区间染色有一面墙, 长度为n, 每次选择一段墙进行染色, m次操作之后, 可以看见多少种颜色数组解决复杂度假如我们使用数组解决这个问题, 那么. 每次染色(更新区间), 需要O(n)的操作.每次查询(查询区间) 需要O(n)的操作另一类问题...

JAVA 内部类的整理记录| 参考JAVA核心卷一第五版_BugGuys的博客-程序员宅基地

内部类定义在类内部的类或方法中的类优势: 内部类方法可以访问该类所在作用于中的任何属性(包含private); 同一包下的其他类无法访问到内部类; 针对回调函数可以使用匿名内部类; public class demo3 { public static void main(String[] args) { User user = n...

Java后端线上问题排查常用命令收藏_程序员小乐的博客-程序员宅基地

点击上方 &#34;编程技术圈&#34;关注,星标或置顶一起成长后台回复“大礼包”有惊喜礼包!每日英文Sometimes it is sunny and sometimes overca...

PHP维护app,PHP app 后端 2 时间有效_weixin_39636540的博客-程序员宅基地

有效时间校验前面的视频里,为了安全,有3个措施1 加密 , 对header里的东西进行加密成一个字符串2 时间有效 , 发起请求里的时间要小于now+设定的有效时间3 唯一性 ,对发起过一次请求,判定没问题后,存在cache里。如果cache里已经有了,说明是多次请求,报error视频中的代码设定时间list($t1, $t2) = explode(' ', microtime());retur...

视频知识点(15)- 一文搞懂 OpenH264 编码库_Data-Mining的博客-程序员宅基地_openh264

目录前言正文1. 下载OpenH264源码2. Windows平台编译环境搭建2.1 安装vs20192.2 安装windows SDK2.3 安装MinGW-w642.4 安装nasm3. 正式编译4. 疑难问题4.1 报错:bash: make: command not found4.2 报错:./gmp-api: No such file or directory.5. 参考评价5.1官方脚本:5.2自定义命令《音视频开发》系列-..

驱动学习4_weixin_30342209的博客-程序员宅基地

1.驱动对象.typedef struct _DRIVER_OBJECT { CSHORT Type; CSHORT Size; // // The following links all of the devices created by a single driver // together on a list, and the Flags...

随便推点

int, string, char*, CString之间的转换_风下残月的博客-程序员宅基地

string转CStringCString cstr;string str = "hello world";str.format("%s",str .c_str());char*转CStringCString cstr;char* pbuf= "hello world";str.format("%s",buf);string转char*string str = "hello world";char* pbuf = str.c_str();CString转stringstring

mysql alter table if exists_如果MySQL中存在列,则使用ALTER删除列_老衲不生气的博客-程序员宅基地

sp00m..12我刚刚建立了一个可重用的程序,可以帮助制作DROP COLUMN幂等法:-- column_exists:DROP FUNCTION IF EXISTS column_exists;DELIMITER $$CREATE FUNCTION column_exists(tname VARCHAR(64),cname VARCHAR(64))RETURNS BOOLEANREADS S...

ueditor搭建图片服务器_普通网友的博客-程序员宅基地

最近用使用富文本编辑器,之前一直使用kindeditor和eWebEditor来着,有同事给推荐说使用百度推出的Ueditor,所以咯,自己新项目就将它引进来了,这里说一下心得,说实话,Ueditor的官网文档真的一般,但是还是能让人看懂的,只不过有些地方写法实在操蛋。不过简单的上手还是很容易的,好了,废话不多说,直接上干货。一、简单的使用 1 &lt;%@ pa...

HashMap、hashTable、ConcurrentHashMap的区别_香瓜西蕉的博客-程序员宅基地

HashMap、hashTable、ConcurrentHashMap的区别1 .HashMap、hashTable、ConcurrentHashMap的概述HashMap是一个散列图,存储的内容是键值对映射hashMap:(java 8 以前):数组+ 链表,结合了两者的优势。操作是非sychronized,效率比较高,默认长度为16,每个数组元素中存储的是链表的头节点。通过位运算获取要存放的位置。最坏情况O(1)-&gt; O(n),运行插入null的值hashmap java8以后采用:

macaca之全局路径_weixin_30883311的博客-程序员宅基地

废话连篇之前刚进行macaca环境配置的时候,直接安装在系统盘C盘内,虽然所占内存不多,但还是有点强迫症想着将其安装在其他磁盘内,所以就找了一些方法,记录下来。实际操作安装好nodejs后就可以进行全局路径的设置,主要使用两个指令,一个主文件,一个是缓存文件:npm config set prefix "***\node_global"npm config set cac...

基于jquery和svg超炫的网页动画_weixin_33908217的博客-程序员宅基地

今天给大家分享一款基于jquery和svg超炫的网页动画。这款动画效果非常炫。下面还有重播、慢速、和反向动画按钮。效果非常漂亮。一起看下效果图:在线预览   源码下载实现的代码。html代码: &amp;lt;div id=&quot;intro&quot;&amp;gt; &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;htt...