概述

上一篇文章,我们主要讲了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加载(四)的更多相关文章

  1. mybatis源码解析之Configuration加载(五)

    概述 前面几篇文章主要看了mybatis配置文件configuation.xml中<setting>,<environments>标签的加载,接下来看一下mapper标签的解析 ...

  2. mybatis源码解析之Configuration加载(三)

    概述 上一篇我们主要分析了下<environments>标签下面,transactionManager的配置,上问最后还有个遗留问题:就是在设置事物管理器的时候有个autocommit的变 ...

  3. mybatis源码解析之Configuration加载(二)

    概述 上一篇我们讲了configuation.xml中几个标签的解析,例如<properties>,<typeAlises>,<settings>等,今天我们来介绍 ...

  4. mybatis源码解析之Configuration加载(一)

    概要 上一篇,我们主要搭建了一个简单的环境,这边我们主要来分析下mybatis是如何来加载它的配置文件Configuration.xml的. 分析 public class App { public ...

  5. 【MyBatis源码分析】Configuration加载(下篇)

    元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...

  6. 【MyBatis源码分析】Configuration加载(上篇)

    config.xml解析为org.w3c.dom.Document 本文首先来简单看一下MyBatis中将config.xml解析为org.w3c.dom.Document的流程,代码为上文的这部分: ...

  7. webpack4.X源码解析之懒加载

    本文针对Webpack懒加载构建和加载的原理,对构建后的源码进行分析. 一.准备工作 首先,init之后创建一个简单的webpack基本的配置,在src目录下创建两个js文件(一个主入口文件和一个非主 ...

  8. Spring源码解析-配置文件的加载

    spring是一个很有名的java开源框架,作为一名javaer还是有必要了解spring的设计原理和机制,beans.core.context作为spring的三个核心组件.而三个组件中最重要的就是 ...

  9. Mybatis源码学习之资源加载(六)

    类加载器简介 Java虚拟机中的类加载器(ClassLoader)负责加载来自文件系统.网络或其他来源的类文件.Java虚拟机中的类加载器默认使用的是双亲委派模式,如图所示,其中有三种默认使用的类加载 ...

随机推荐

  1. 面试被问之-----sql优化中in与exists的区别

    曾经一次去面试,被问及in与exists的区别,记得当时是这么回答的:''in后面接子查询或者(xx,xx,xx,,,),exists后面需要一个true或者false的结果",当然这么说也 ...

  2. 【HNOI 2016】序列

    Problem Description 给定长度为 \(n\) 的序列:\(a_1, a_2, \cdots , a_n\),记为 \(a[1 \colon n]\).类似地,\(a[l \colon ...

  3. scipy插值与拟合

    原文链接:https://zhuanlan.zhihu.com/p/28149195 1.最小二乘拟合 实例1 import numpy as np import matplotlib.pyplot ...

  4. golang协程踩坑记录

    1.主线程等待多个协程执行完毕后,再执行下面的程序.golang提供了一个很好用的工具. sync.WaitGroup下面是个简单的例子. 执行结果: 2.主线程主动去结束已经启动了的多个协程.执行结 ...

  5. spring cloud 初体验

    spring cloud分为注册端.客户端以及消费端 初体验的理解就是: 注册端就是将之前所有的应用在这边进行注册,然后给每个应用都生成自己的标识,这些应用就是来自于客户端,消费端则通过调用注册端(有 ...

  6. Active Record Query Interface 数据查询接口(界面) 看到第8节。

    http://guides.rubyonrails.org/active_record_querying.html ✅How to find records using a variety of me ...

  7. 杂记:防火墙、企业微信登陆、RestFrameWork

    192.168.0.250重启后查看端口正常,外部ping得通,但是访问192.168.0.250进不了Nginx欢迎界面 netstat -tlunp 关闭了防火墙就行了,原来80端口都要防火墙. ...

  8. Vue.js——60分钟快速入门(转)

    vue:Vue.js——60分钟快速入门 <!doctype html> <html lang="en"> <head> <meta ch ...

  9. vue中<select>绑定事件

    <div id="app"> <select v-model="selectItem" @change="selectFn($eve ...

  10. CF数据结构练习(二)

    1. 833D Red-Black Cobweb 大意: 给定树, 边为黑色或白色, 求所有黑白边比例在$[\frac{1}{2},2]$内的路径边权乘积的乘积. 考虑点分治, 记黑边数为$a$, 白 ...