概述

上一篇文章,我们主要讲了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的解析过程。

最新文章

  1. Orchard源码分析(5.3):EndRequest事件处理(DefaultOrchardHost.EndRequest方法)
  2. Java Serializable(序列化)
  3. ipseccmd命令解析
  4. C#的Socket简单实现消息发送
  5. Asp.Net Web API VS Asp.Net MVC
  6. [网络]关于公网IP的一些事
  7. 定义任务打印gradle下载的jar包位置
  8. JS操作性能优化
  9. crtmpserver组网方案
  10. java通过JNI接口调用C语言-初级
  11. 卷积神经网络总结CNN【转载】
  12. Ocelot简易教程(一)之Ocelot是什么
  13. Vue指令v-for之遍历输出JavaScript数组,json对象的几种方式
  14. Linux系统mysql使用(二)
  15. lightoj 1220 唯一分解定理
  16. Integrating Jenkins and Apache Tomcat for Continuous Deployment
  17. EasyUI动态修改easyui-textbox验证信息
  18. lesson4Embedding-fastai
  19. hdu 5056 所有字母数都&lt;=k的子串数目
  20. Linux中找出占用内存最多的前N个进程

热门文章

  1. Qt setstylesheet指定窗口
  2. 【BUAA-OO】第二单元作业总结
  3. python笔记—循环控制
  4. radio为什么不能选择。急急急
  5. 自身使用的springboot项目中比较全的pom.xml
  6. java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details
  7. vbuffer.hpp
  8. 在线批量将gps经纬度坐标转换为百度经纬度坐标
  9. Lyrics来源
  10. 关于index.html被缓存问题