概述

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

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. Navicat Premium 12

    1.win 客户端软件下载: https://www.navicat.com.cn/download/navicat-premium 2.安装 双击安装--点击下一步 我同意--下一步 选择安装路径- ...

  2. 读《流畅的python》第一天

    1.跟运算符无关的特殊方法了解: 2.跟运算符相关的特殊方法了解: 3.内置的序列类型分类: 容器序列 list.tuple 和 collections.deque 这些序列能存放不同类型的数据. 扁 ...

  3. 解决js的 Math取正弦值 余弦值不准确的问题

    //角度 var  vAngle=90: //正弦值 var vSin=Math.round(Math.sin((vAngle * Math.PI/180)) * 1000000) / 1000000 ...

  4. vector某元素是否存在、查找指定元素 、去重

    vector.map 判断某元素是否存在.查找指定元素 [C++]判断元素是否在vector中,对vector去重,两个vector求交集.并集 PS:注意重载

  5. Docker Swarm Mode 学习笔记 (部署服务)

    使用 docker service 命令来管理 Swarm 集群中的服务,该命令只能在管理节点上执行. 新建服务 docker service create --replicas 3 -p 80:80 ...

  6. thinkphp 操作xml格式

    前言:虽然xml的格式看起来跟html差不多,但是最近做项目由于用的是thinkphp5.0的版本,做的过程中还是遇到了一些问题.在这里做一下记录. 首先我们需要定义一个dom对象,我们都知道 php ...

  7. UP_GetRecordByPage

    CREATE PROCEDURE [dbo].[UP_GetRecordByPage] @tblName varchar(255), -- 表名 @fldName varchar(255), -- 主 ...

  8. 集训队日常训练20181201 C 1003 : 种类数

    时间限制(普通/Java):2000MS/6000MS     内存限制:65536KByte总提交: 8            测试通过:5 描述 一共有 n个数,第 i 个数是 xi ,其中xi  ...

  9. windows 根据端口查看进行PID 并杀掉进程

    1. 首先用netstat -ano | find “端口号”查出进程号 明明有端口号是17568和18892, 如何确定是17568呢 2. takslist 查询当前的进行 3. 如何杀死进程呢  ...

  10. Oracle高级查询之over(partition by...)

    现有表,数据如下: eg1:查询年龄第二的队员 通常写法: select * from (select a.*, rownum r from (select t.* from l_student_in ...