MyBatis源码解析(二)——Environment环境
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6625612.html
本应该先开始说Configuration配置类的,但是这个类有点过于复杂,因为MyBatis中的所有配置项全部在这个类中,可谓包罗万象,一开始就讨论如此高大上的东西,貌似有点不合适,认识和学习都应该从小开始,从基础开始,所以我做了这样一个小安排,先挑Configuration中重要的配置项进行了解,心中有了大概印象之后,在进行Configuration的解读,这样就能较为轻松的接受整个其中复杂的配置信息,而不至于不知所措。
首先我们来看看Environment——环境
先说说我们熟悉的内容,当我们单独使用MyBatis框架时(不与Spring框架整合),是需要在Configuration.xml配置文件中进行环境配置的,其代码如下:
1 <environments default="development"> 2 <environment id="development"> 3 <transactionManager type="JDBC"/> 4 <dataSource type="POOLED"> 5 <property name="driver" value="com.mysql.jdbc.Driver"/> 6 <property name="url" value="jdbc:mysql://localhost:3306/mbtest"/> 7 <property name="username" value="root"/> 8 <property name="password" value="123456"/> 9 </dataSource> 10 </environment> 11 </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类的源码
1 package org.apache.ibatis.mapping; 2 import javax.sql.DataSource; 3 import org.apache.ibatis.transaction.TransactionFactory; 4 /** 5 * 环境 6 * 决定加载哪种环境(开发环境/生产环境) 7 */ 8 public final class Environment { 9 //环境id 10 private final String id; 11 //事务工厂 12 private final TransactionFactory transactionFactory; 13 //数据源 14 private final DataSource dataSource; 15 public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) { 16 if (id == null) { 17 throw new IllegalArgumentException("Parameter 'id' must not be null"); 18 } 19 if (transactionFactory == null) { 20 throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null"); 21 } 22 this.id = id; 23 if (dataSource == null) { 24 throw new IllegalArgumentException("Parameter 'dataSource' must not be null"); 25 } 26 this.transactionFactory = transactionFactory; 27 this.dataSource = dataSource; 28 } 29 //一个静态内部类Builder 30 //建造模式 31 //用法应该是new Environment.Builder(id).transactionFactory(xx).dataSource(xx).build(); 32 public static class Builder { 33 private String id; 34 private TransactionFactory transactionFactory; 35 private DataSource dataSource; 36 public Builder(String id) { 37 this.id = id; 38 } 39 public Builder transactionFactory(TransactionFactory transactionFactory) { 40 this.transactionFactory = transactionFactory; 41 return this; 42 } 43 public Builder dataSource(DataSource dataSource) { 44 this.dataSource = dataSource; 45 return this; 46 } 47 public String id() { 48 return this.id; 49 } 50 public Environment build() { 51 return new Environment(this.id, this.transactionFactory, this.dataSource); 52 } 53 } 54 public String getId() { 55 return this.id; 56 } 57 public TransactionFactory getTransactionFactory() { 58 return this.transactionFactory; 59 } 60 public DataSource getDataSource() { 61 return this.dataSource; 62 } 63 }
通过源码我们可以发现,在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这两个内容又是两大块内容,这一部分容后介绍。
自己理解的还很浅显,希望随着不断的解读源码,能够提升自己的认识,到时候再来这里进行进一步改进。
(未完待续)
转载于:https://www.cnblogs.com/V1haoge/p/6625612.html
MyBatis源码解析(二)——Environment环境相关推荐
- Mybatis源码解析(一):环境搭建
Mybatis源码系列文章 手写源码(了解源码整体流程及重要组件) Mybatis源码解析(一):环境搭建 Mybatis源码解析(二):全局配置文件的解析 Mybatis源码解析(三):映射配置文件 ...
- Mybatis源码解析《二》
导语 在前一篇文章Mybatis源码解析<一>中,已经简单了捋了一下mybatis核心文件和mapper配置文件的一个基本的解析流程,这是理解mybatis的基本,和spring中的配置文 ...
- mybatis源码阅读(二):mybatis初始化上
转载自 mybatis源码阅读(二):mybatis初始化上 1.初始化入口 //Mybatis 通过SqlSessionFactory获取SqlSession, 然后才能通过SqlSession与 ...
- mybatis源码解析(一)
Mybatis 源码解析 (一) 一. ORM框架的作用 实际开发系统时,我们可通过JDBC完成多种数据库操作.这里以传统JDBC编程过程中的查询操作为例进行说明,其主要步骤如下: (1)注册数据库驱 ...
- mybatis源码考究二(sqlsession线程安全和缓存失效)
mybatis源码考究二 1.mybatis整合spring解决sqlsession线程安全问题 2.mybatis整合spring一级缓存失效问题 mybatis结合spring使用 1.项目依赖 ...
- 对标阿里P8的MyBatis源码解析文档,面试/涨薪两不误,已献出膝盖
移动互联网的特点是大数据.高并发,对服务器往往要求分布式.高性能.高灵活等,而传统模式的Java数据库编程框架已经不再适用了. 在这样的背景下,一个Java的持久框架MyBatis走入了我们的世界,它 ...
- mybatis源码解析1_sessionFactory
注 一下内容都是根据尚硅谷2018年mybatis源码解析做的课程笔记,视频链接: https://www.bilibili.com/video/BV1mW411M737?p=74&share ...
- 【MyBatis源码解析】MyBatis一二级缓存
MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...
- mybatis源码解析一 xml解析(解析器)
最近闲来无事,看着一些源码类的书籍,只是光看,好像并不能给自己很好的益处,无法记下来,所以就有了这个Mybatis源码解析系列的博客.网上也有大量的源码解析,在此记录有两个原因,一是为了加深自己的印象 ...
- 【深度学习模型】智云视图中文车牌识别源码解析(二)
[深度学习模型]智云视图中文车牌识别源码解析(二) 感受 HyperLPR可以识别多种中文车牌包括白牌,新能源车牌,使馆车牌,教练车牌,武警车牌等. 代码不可谓不混乱(别忘了这是职业公司的准产品级代码 ...
最新文章
- NFS简单应用场景及简单的环境搭建
- 火车票上的星号暗藏玄机?!
- [转帖]虚拟内存探究 -- 第二篇:Python 字节
- PHP图片间隙用什么代码,如何解决CSS图片下面有间隙的问题
- java 9 module_Java 9:欢迎来到Module World
- 从GAN到WGAN到LipschitzGA
- 棘手的问题input:当在严格模式中使用 Vuex 时,在属于 Vuex 的 state 上使用 v-model,input
- 使用FragmentTabHost+Fragment+viewpager 实现滑动分页
- TCP的send与recv函数小结
- IntelliJ IDEA 更换背景图和背景颜色
- ShuffleNet 系列(1): ShuffleNet v1 理论讲解
- 安装黑苹果时提示未能与服务器,黑苹果安装提示:不能验证这个“安装 OS X EI Capitan”应用程序副本解决方法 _ 黑苹果乐园...
- 批量重命名,文件夹重命名的五种方式分享
- java启动绑定网卡_ServerSocket 默认邦定IP
- 真无线蓝牙耳机推荐:2021最受欢迎的TWS耳机品牌
- Spark的shuffle机制
- adb命令查看手机电量_使用adb命令查看电池电量信息
- 提升客户生命周期价值(CLV)的5大方法
- 使用Gitee+Hexo搭建高速稳定的个人博客
- win10 IE自动跳转到EDGE的解决办法(注册表)
热门文章
- 安装和配置sendmail
- linux命令大写输入,在Linux命令行内的大小写转换
- .html .php .asp,html静态页面中执行php、asp函数代码
- db2 修改表空间自增长_db2表空间及日志文件调整
- mysql 更改数据库编码_更改MySQL数据库的编码为utf8mb4
- python程序运行时间计时软件_python中的计时器timeit的使用方法
- 【干货】常用的Linux 系统备份、恢复命令
- 课时 30:理解 RuntimeClass 与使用多容器运行时(贾之光)
- 冒号运算 java_java 8 双冒号运算符
- 简书markdown支持html,简书上使用Markdown(超详细)