MyBatis源码解析(二)——Environment环境
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6625612.html
本应该先开始说Configuration配置类的,但是这个类有点过于复杂,因为MyBatis中的所有配置项全部在这个类中,可谓包罗万象,一开始就讨论如此高大上的东西,貌似有点不合适,认识和学习都应该从小开始,从基础开始,所以我做了这样一个小安排,先挑Configuration中重要的配置项进行了解,心中有了大概印象之后,在进行Configuration的解读,这样就能较为轻松的接受整个其中复杂的配置信息,而不至于不知所措。
首先我们来看看Environment——环境
先说说我们熟悉的内容,当我们单独使用MyBatis框架时(不与Spring框架整合),是需要在Configuration.xml配置文件中进行环境配置的,其代码如下:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mbtest"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
从上面的配置内容中可以看出,标签environment代表的就是环境,其有一个属性id,值为“development”(表示开发环境,对应的还会有生产环境),而在其下级节点还需要配置两个内容:transactionManager和DataSource,前者是事务管理器,后者是数据源。“JDBC”表示事务管理器是JDBC类型了,这个标签对应Configuration类创建时在其无参构造器中注册的类型别名,通过这个类型别名注册信息可以找到实际的JDBC事务工厂类:JdbcTransactionFactory(JDBC事务工厂,这个类之后会介绍到,稍安勿躁)。而数据源的类型为“POOLED”类型,同样可以在Configuration类的无参构造器中找到对应的注册信息:PooledDataSourceFactory(表示有连接池的数据源工厂,这个类之后也会介绍)。
而我们要介绍的Environment类就是这个environment标签所代表的环境类,构建Configuration之前,第一步是进行类型别名注册,第二步就是将Environment配置内容从配置文件中读入Environment类中(这一步是在XMLConfigBuilder中完成的),并将其组合到Configuration类中。
Environment类位于org.apache.ibatis.mapping包下,整个类被final修饰,这意味着这个类是个最终类,就如String类一样,是一个不可被更改的类,即其实例是唯一的不能被轻易修改。
下方列出Environment类的源码
package org.apache.ibatis.mapping;
import javax.sql.DataSource;
import org.apache.ibatis.transaction.TransactionFactory;
/**
* 环境
* 决定加载哪种环境(开发环境/生产环境)
*/
public final class Environment {
//环境id
private final String id;
//事务工厂
private final TransactionFactory transactionFactory;
//数据源
private final DataSource dataSource;
public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
if (id == null) {
throw new IllegalArgumentException("Parameter 'id' must not be null");
}
if (transactionFactory == null) {
throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");
}
this.id = id;
if (dataSource == null) {
throw new IllegalArgumentException("Parameter 'dataSource' must not be null");
}
this.transactionFactory = transactionFactory;
this.dataSource = dataSource;
}
//一个静态内部类Builder
//建造模式
//用法应该是new Environment.Builder(id).transactionFactory(xx).dataSource(xx).build();
public static class Builder {
private String id;
private TransactionFactory transactionFactory;
private DataSource dataSource;
public Builder(String id) {
this.id = id;
}
public Builder transactionFactory(TransactionFactory transactionFactory) {
this.transactionFactory = transactionFactory;
return this;
}
public Builder dataSource(DataSource dataSource) {
this.dataSource = dataSource;
return this;
}
public String id() {
return this.id;
}
public Environment build() {
return new Environment(this.id, this.transactionFactory, this.dataSource);
}
}
public String getId() {
return this.id;
}
public TransactionFactory getTransactionFactory() {
return this.transactionFactory;
}
public DataSource getDataSource() {
return this.dataSource;
}
}
通过源码我们可以发现,在Environment类中有三个字段:id、transactionFactory、dataSource,分别对应于配置文件中的三个配置项(id、transactionManager、DataSource),而且这三项均为final类型,表示不可被更改,一次设置终身有效,所以在整个类中也只是使用三参构造器为三项字段赋值,而没有set方法可以进行字段值的更改,只有get方法,可以获取到设置的信息。
Environment类内部有一个静态内部类Builder,这显然是一个构建器类,所以Environgment实例的创建使用了构建者模式(也叫建造者模式)。我们当然可以直接使用外部类的构造器直接进行实例创建,但这并不是MyBatis推荐的(当然其实也不会要求你去手动创建Environgment实例,这里只是打个比方),MyBatis内部进行Environgment实例创建时,就是用其内部构建者进行创建,创建方式和源码中注释里一样:
new Environment.Builder(id).transactionFactory(xx).dataSource(xx).build();
为什么要使用构建者模式呢?那让我们来回忆一下构建者模式的内容。
构建者模式一般用于构建复杂对象时,将复杂对象分割成许多小对象进行分别构建,然后整合在一起形成一个大对象,这样做能很好的规范对象构建的细节过程,这里也是一样的目的,虽然说Environment类的字段较少,但在MyBatis中大量使用构建者模式的基础上,在此处使用构建者模式也无可厚非,而且通过内部类的方式构建,这个Environment对象的创建会在内部类构建方法build()被显式调用时才会在内存中创建,实现了懒加载。这又有点单例模式的意思在内,虽然Mybatis中可创建多个Environment环境,但是在正式运行时,只会存在一个环境,确实是使用内部类实现了懒加载的单例模式。
这个实例的创建最显然的使用位置就是在XMLConfigBuilder构建器中解析构建Configuration类时在解析了Configuration.xml配置文件中environment标签的内容之后,这个位置用于将读自于配置文件的配置信息配置到了Environment对象中。(这句话有点拗口,不要着急,这个过程在以后介绍XMLConfigBuilder类时会有介绍的)
其实这个类很简单,但它内部包含的TracsactionFactory和DataSource这两个内容又是两大块内容,这一部分容后介绍。
自己理解的还很浅显,希望随着不断的解读源码,能够提升自己的认识,到时候再来这里进行进一步改进。
(未完待续)
MyBatis源码解析(二)——Environment环境的更多相关文章
- Mybatis源码解析(二) —— 加载 Configuration
Mybatis源码解析(二) -- 加载 Configuration 正如上文所看到的 Configuration 对象保存了所有Mybatis的配置信息,也就是说mybatis-config. ...
- Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码
在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...
- mybatis源码-解析配置文件(三)之配置文件Configuration解析
目录 1. 简介 1.1 系列内容 1.2 适合对象 1.3 本文内容 2. 配置文件 2.1 mysql.properties 2.2 mybatis-config.xml 3. Configura ...
- Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例
在Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们看到了XMLConfigBuilder(xml配置解析器)的实例化.而且这个实例化过程在文章:Mybatis源码解析,一步一步从浅 ...
- Mybatis源码解析,一步一步从浅入深(一):创建准备工程
Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...
- Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)
在上一篇文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 ,中我们看到 代码:XMLConfigBuilder parser = new XMLConfigBuilder(read ...
- Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析
在上一篇文章Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例中我们谈到了properties,settings,envir ...
- Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?
Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? 如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...
- [源码解析] TensorFlow 分布式环境(1) --- 总体架构
[源码解析] TensorFlow 分布式环境(1) --- 总体架构 目录 [源码解析] TensorFlow 分布式环境(1) --- 总体架构 1. 总体架构 1.1 集群角度 1.1.1 概念 ...
- mybatis源码-解析配置文件(四)之配置文件Mapper解析
在 mybatis源码-解析配置文件(三)之配置文件Configuration解析 中, 讲解了 Configuration 是如何解析的. 其中, mappers作为configuration节点的 ...
随机推荐
- Vue控制路由滚动行为
跳转路由时,要求跳转到指定路由的某个地方,可以使用scrollBehavior方法控制. 用法: scrollBehavior(to,from,savedPosition){ } scrollBe ...
- java开发师笔试面试每日12题(3)
1.JDK和JRE的区别是什么? Java运行时环境(JRE)是将要执行Java程序的Java虚拟机.它同时也包含了执行applet需要的浏览器插件.Java开发工具包(JDK)是完整的Java软件开 ...
- scrapy的基础概念和流程
1. 什么是scrapy Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,我们只需要实现少量的代码,就能够快速的抓取. Scrapy 使用了Twisted['twɪstɪd]异步网 ...
- Python学习过程中各个难点---函数篇
对于函数,我一直分不清局部变量与全局变量,今天又好好研究了下,终于搞清楚了. 例子: 其次对于global这个关键字我也是一知半解的状态,之前整个人都是懵懵的,现在搞明白了 匿名函数: 匿名函数使用关 ...
- 我的C#跨平台之旅(三):使用Entity Framework开发REST API
添加NuGet引用:EntityFramework 创建实体类:Book.Author 以及数据传输类:BookDTO.BookDetailDTO,代码如下: 创建DbContext类:BookDbC ...
- Oracle数据库---用户与角色
Oracle数据库---用户与角色 2019年02月26日 10:56:10 俊杰梓 阅读数:21 标签: 数据库 更多 个人分类: 数据库 版权声明:版权所有,转载请注明出处.谢谢 https: ...
- jQuery-事件命名空间
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 黑群晖DS3617xs-DSM6.1.7up3/up2 开启ROOT用户,同时SATA改eSATA,挂载NTFS硬盘设置(二)
这两天闲来没事在某宝上搞了个黑群晖主机就j1900/4G小主机系统是DCM 6.1.7up3 15284版 网上修改的教程很多,走了好多弯路终于搞定我的黑群NAS,现分享给各位道友,有不足的地方请给位 ...
- Django 搭建博客记(二)
当前博客实现的功能 实现 Markdown 语法功能 python 安装 markdown 模块 添加 markdown 过滤 实现代码高亮 通过 CSS 样本实现 分页功能 简单的关于页面和标签分类 ...
- Node.js的安装以及npm的基础使用
索引: Node.js的安装以及Node.js的模块管理Node.js开发环境搭建以及对ES6的支持Node.js构建Vue.js项目Vue.js单文件组件的开发基于Vue.js的UI组件(Eleme ...