厨房小码农

mybatis源码解析之Configuration加载(四)

概述

上一篇文章,我们主要讲了datasource的相关内容,那么<environments>标签下的内容就看的差不多了,今天就来看一下在拿到transationManager和datasource之后,mybatis又做了什么事情呢?

Environment类

 我们先来看下解析<environments>标签的那段代码:

 1   private void environmentsElement(XNode context) throws Exception {
 2     if (context != null) {
 3       if (environment == null) {
 4         environment = context.getStringAttribute("default");
 5       }
 6       for (XNode child : context.getChildren()) {
 7         String id = child.getStringAttribute("id");
 8         if (isSpecifiedEnvironment(id)) {
 9           TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
10           DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
11           DataSource dataSource = dsFactory.getDataSource();
12           Environment.Builder environmentBuilder = new Environment.Builder(id)
13               .transactionFactory(txFactory)
14               .dataSource(dataSource);
15           configuration.setEnvironment(environmentBuilder.build());
16         }
17       }
18     }
19   }

我们看一下12-15行代码,12-14行主要就是创建了一个Environment.Builder类,将之前获取到的id,transationManager,datasource放进去,第15行代码,调用build方法获取environment对象,并将其放进configuation中。逻辑上很简单,但是写法上有点奇怪,一下子还不怎么看得懂,连续点了这么多的方法,我们来研究下这么写的好处?

首先我们来看下Environment类的内容:

 1 public final class Environment {
 2   private final String id;
 3   private final TransactionFactory transactionFactory;
 4   private final DataSource dataSource;
 5 
 6   public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
 7     if (id == null) {
 8       throw new IllegalArgumentException("Parameter 'id' must not be null");
 9     }
10     if (transactionFactory == null) {
11         throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");
12     }
13     this.id = id;
14     if (dataSource == null) {
15       throw new IllegalArgumentException("Parameter 'dataSource' must not be null");
16     }
17     this.transactionFactory = transactionFactory;
18     this.dataSource = dataSource;
19   }
20 
21   public static class Builder {
22       private String id;
23       private TransactionFactory transactionFactory;
24       private DataSource dataSource;
25 
26     public Builder(String id) {
27       this.id = id;
28     }
29 
30     public Builder transactionFactory(TransactionFactory transactionFactory) {
31       this.transactionFactory = transactionFactory;
32       return this;
33     }
34 
35     public Builder dataSource(DataSource dataSource) {
36       this.dataSource = dataSource;
37       return this;
38     }
39 
40     public String id() {
41       return this.id;
42     }
43 
44     public Environment build() {
45       return new Environment(this.id, this.transactionFactory, this.dataSource);
46     }
47 
48   }
49 
50   public String getId() {
51     return this.id;
52   }
53 
54   public TransactionFactory getTransactionFactory() {
55     return this.transactionFactory;
56   }
57 
58   public DataSource getDataSource() {
59     return this.dataSource;
60   }
61 
62 }

看第1行代码,这个类被final修饰,这个跟String等不可变类有点像,一旦创建了,就不能再改变了。

这个类有三个类变量,分别是 id,transationfactory,datasource,分别对应于配置文件中的三个配置项(id、transactionManager、DataSource),这几个我们之前已经分析过了,这个几个字段也分别被final修饰,一旦设置,就不能再修改,而且针对这几个字段,类里面只提供了get方法,没有set方法(反正也不能修改),只能够去获取配置设定的值,而不能修改。

在源码里面,我们看到这个类里面有一个静态内部类,Builder,内容如下:

 1   public static class Builder {
 2       private String id;
 3       private TransactionFactory transactionFactory;
 4       private DataSource dataSource;
 5 
 6     public Builder(String id) {
 7       this.id = id;
 8     }
 9 
10     public Builder transactionFactory(TransactionFactory transactionFactory) {
11       this.transactionFactory = transactionFactory;
12       return this;
13     }
14 
15     public Builder dataSource(DataSource dataSource) {
16       this.dataSource = dataSource;
17       return this;
18     }
19 
20     public String id() {
21       return this.id;
22     }
23 
24     public Environment build() {
25       return new Environment(this.id, this.transactionFactory, this.dataSource);
26     }
27 
28   }

这种写法熟悉设计模式的朋友肯定一眼就看出来了,这里使用了构造者模式,将创建Environment 对象的过程分了好几个步骤,先设置id,再设置transactionFactory,接着是dataSource,最后可以调用build方法,返回Environment对象。为什么要用这种写法呢?

我们先来回顾下什么建造者模式:

构建者模式一般用于构建复杂对象时,将复杂对象分割成许多小对象进行分别构建,然后整合在一起形成一个大对象,这样做能很好的规范对象构建的细节过程,这里也是一样的目的,虽然说Environment类的字段较少,但在MyBatis中大量使用构建者模式的基础上,在此处使用构建者模式也无可厚非,而且通过内部类的方式构建,这个Environment对象的创建会在内部类构建方法build()被显式调用时才会在内存中创建,实现了懒加载。这又有点单例模式的意思在内,虽然Mybatis中可创建多个Environment环境,但是在正式运行时,只会存在一个环境,确实是使用内部类实现了懒加载的单例模式。

好了,到这里关于<environments>标签的分析就结束了,后面我们分析下mappers的解析过程。

posted on 2018-12-29 11:53  厨房小码农  阅读(275)  评论(0编辑  收藏  举报

导航