mybatis源码解析之Configuration加载(四)
概述
上一篇文章,我们主要讲了datasource的相关内容,那么<environments>标签下的内容就看的差不多了,今天就来看一下在拿到transationManager和datasource之后,mybatis又做了什么事情呢?
Environment类
我们先来看下解析<environments>标签的那段代码:
   private void environmentsElement(XNode context) throws Exception {
     if (context != null) {
       if (environment == null) {
         environment = context.getStringAttribute("default");
       }
       for (XNode child : context.getChildren()) {
         String id = child.getStringAttribute("id");
         if (isSpecifiedEnvironment(id)) {
           TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
           DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
           DataSource dataSource = dsFactory.getDataSource();
           Environment.Builder environmentBuilder = new Environment.Builder(id)
               .transactionFactory(txFactory)
               .dataSource(dataSource);
           configuration.setEnvironment(environmentBuilder.build());
         }
       }
     }
   }
我们看一下12-15行代码,12-14行主要就是创建了一个Environment.Builder类,将之前获取到的id,transationManager,datasource放进去,第15行代码,调用build方法获取environment对象,并将其放进configuation中。逻辑上很简单,但是写法上有点奇怪,一下子还不怎么看得懂,连续点了这么多的方法,我们来研究下这么写的好处?
首先我们来看下Environment类的内容:
 public final class Environment {
   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;
   }
   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;
   }
 }
看第1行代码,这个类被final修饰,这个跟String等不可变类有点像,一旦创建了,就不能再改变了。
这个类有三个类变量,分别是 id,transationfactory,datasource,分别对应于配置文件中的三个配置项(id、transactionManager、DataSource),这几个我们之前已经分析过了,这个几个字段也分别被final修饰,一旦设置,就不能再修改,而且针对这几个字段,类里面只提供了get方法,没有set方法(反正也不能修改),只能够去获取配置设定的值,而不能修改。
在源码里面,我们看到这个类里面有一个静态内部类,Builder,内容如下:
   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);
     }
   }
这种写法熟悉设计模式的朋友肯定一眼就看出来了,这里使用了构造者模式,将创建Environment 对象的过程分了好几个步骤,先设置id,再设置transactionFactory,接着是dataSource,最后可以调用build方法,返回Environment对象。为什么要用这种写法呢?
我们先来回顾下什么建造者模式:
构建者模式一般用于构建复杂对象时,将复杂对象分割成许多小对象进行分别构建,然后整合在一起形成一个大对象,这样做能很好的规范对象构建的细节过程,这里也是一样的目的,虽然说Environment类的字段较少,但在MyBatis中大量使用构建者模式的基础上,在此处使用构建者模式也无可厚非,而且通过内部类的方式构建,这个Environment对象的创建会在内部类构建方法build()被显式调用时才会在内存中创建,实现了懒加载。这又有点单例模式的意思在内,虽然Mybatis中可创建多个Environment环境,但是在正式运行时,只会存在一个环境,确实是使用内部类实现了懒加载的单例模式。
好了,到这里关于<environments>标签的分析就结束了,后面我们分析下mappers的解析过程。
mybatis源码解析之Configuration加载(四)的更多相关文章
- mybatis源码解析之Configuration加载(五)
		
概述 前面几篇文章主要看了mybatis配置文件configuation.xml中<setting>,<environments>标签的加载,接下来看一下mapper标签的解析 ...
 - mybatis源码解析之Configuration加载(三)
		
概述 上一篇我们主要分析了下<environments>标签下面,transactionManager的配置,上问最后还有个遗留问题:就是在设置事物管理器的时候有个autocommit的变 ...
 - mybatis源码解析之Configuration加载(二)
		
概述 上一篇我们讲了configuation.xml中几个标签的解析,例如<properties>,<typeAlises>,<settings>等,今天我们来介绍 ...
 - mybatis源码解析之Configuration加载(一)
		
概要 上一篇,我们主要搭建了一个简单的环境,这边我们主要来分析下mybatis是如何来加载它的配置文件Configuration.xml的. 分析 public class App { public ...
 - 【MyBatis源码分析】Configuration加载(下篇)
		
元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...
 - 【MyBatis源码分析】Configuration加载(上篇)
		
config.xml解析为org.w3c.dom.Document 本文首先来简单看一下MyBatis中将config.xml解析为org.w3c.dom.Document的流程,代码为上文的这部分: ...
 - webpack4.X源码解析之懒加载
		
本文针对Webpack懒加载构建和加载的原理,对构建后的源码进行分析. 一.准备工作 首先,init之后创建一个简单的webpack基本的配置,在src目录下创建两个js文件(一个主入口文件和一个非主 ...
 - Spring源码解析-配置文件的加载
		
spring是一个很有名的java开源框架,作为一名javaer还是有必要了解spring的设计原理和机制,beans.core.context作为spring的三个核心组件.而三个组件中最重要的就是 ...
 - Mybatis源码学习之资源加载(六)
		
类加载器简介 Java虚拟机中的类加载器(ClassLoader)负责加载来自文件系统.网络或其他来源的类文件.Java虚拟机中的类加载器默认使用的是双亲委派模式,如图所示,其中有三种默认使用的类加载 ...
 
随机推荐
- Manjaro 安装svn客户端,以及checkout使用命令
			
安装svn sudo pacman -S svn checkout操作指令 svn co http://xxxxxxx /home/xx update 更新版本 svn up [文件/目录] 直接使用 ...
 - Valse2019笔记——弱监督视觉理解
			
程明明(南开大学):面向开放环境的自适应视觉感知 (图片来自valse2019程明明老师ppt) 面向识别与理解的神经网络共性技术 深度神经网络通用架构 -- VggNet(ICLR'15).ResN ...
 - 使用RStudio调试(debug)基础学习(二)和fGarch包中的garchFit函数估计GARCH模型的原理和源码
			
一.garchFit函数的参数--------------------------------------------- algorithm a string parameter that deter ...
 - 给video添加自定义进度条
			
思路: 1.进度条,首先要知道视频的总长度,和视频的当前进度,与其对应的便是进度条的总长度和当前的长度,两者比值相等 2.获取视频的总长度(单位是秒),获取当前进度 3.要实现的功能,首先是进度条根据 ...
 - 用 jupyter notebook 打开 oui.txt 文件出现的问题及解决方案
			
问题背景:下载了2018 IEEE 最新的 oui.txt 文件.里面包含了 设备 MAC 地址的前六位对应的厂商.要做的工作是,将海量设备的 MAC 地址与 oui.txt 文件的信息比对,统计出 ...
 - Linux下安装docker
			
//安装docker //需要输入时 输y就可以yum install -y epel-releaseyum install docker-io # 加入开机启动chkconfig docker on ...
 - OpenGL.教程
			
5.第五课:带纹理的立方体.html(http://www.opengl-tutorial.org/cn/beginners-tutorials/tutorial-5-a-textured-cube/ ...
 - Java ----> java io / java nio / java net 学习资源汇总
			
Java IO教程 Java NIO 系列教程 Java网络教程 学习Java基础的一个英文网站:http://tutorials.jenkov.com/ ,上面中文教程来自并发编程网,上面中文教程翻 ...
 - 持续集成CI/CD
			
Gitlab+kubernetes+docker+jenkins+harbor搭建持续交付系统 http://blog.chenmiao.cf/2016/12/28/gitlab+kubernetes ...
 - f-stack nginx多进程报错 primary worker process failed to initialize
			
EAL: Detected 4 lcore(s)EAL: Detected 1 NUMA nodesEAL: Multi-process socket /var/run/dpdk/rte/mp_soc ...