首页 Java java教程 深入浅出Mybatis系列(三)--配置详解之properties与environments(mybatis源码篇)

深入浅出Mybatis系列(三)--配置详解之properties与environments(mybatis源码篇)

Mar 02, 2017 am 10:40 AM

上篇文章《深入浅出Mybatis系列(二)---配置简介(mybatis源码篇)》我们通过对mybatis源码的简单分析,可看出,在mybatis配置文件中,在configuration根节点下面,可配置properties、typeAliases、plugins、objectFactory、objectWrapperFactory、settings、environments、databaseIdProvider、typeHandlers、mappers这些节点。那么本次,就会先介绍properties节点和environments节点。

  为了让大家能够更好地阅读mybatis源码,我先简单的给大家示例一下properties的使用方法。  

1 <configuration> 
2 <!-- 方法一: 从外部指定properties配置文件, 除了使用resource属性指定外,还可通过url属性指定url  
 3   <properties resource="dbConfig.properties"></properties> 
 4   --> 
 5   <!-- 方法二: 直接配置为xml --> 
 6   <properties> 
 7       <property name="driver" value="com.mysql.jdbc.Driver"/> 
 8       <property name="url" value="jdbc:mysql://localhost:3306/test1"/> 
 9       <property name="username" value="root"/>
 10       <property name="password" value="root"/>
 11   </properties>
登录后复制


  那么,我要是 两种方法都同时用了,那么哪种方法优先?

  当以上两种方法都xml配置优先, 外部指定properties配置其次。至于为什么,接下来的源码分析会提到,请留意一下。

  再看一下envirements元素节点的使用方法吧:

<environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
          <!--
          如果上面没有指定数据库配置的properties文件,那么此处可以这样直接配置 
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test1"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>         -->
         
         <!-- 上面指定了数据库配置文件, 配置文件里面也是对应的这四个属性 -->
         <property name="driver" value="${driver}"/>
         <property name="url" value="${url}"/>
         <property name="username" value="${username}"/>
         <property name="password" value="${password}"/>
         
      </dataSource>
    </environment>
    
    <!-- 我再指定一个environment -->
    <environment id="test">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <!-- 与上面的url不一样 -->
        <property name="url" value="jdbc:mysql://localhost:3306/demo"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
    
  </environments>
登录后复制


  environments元素节点可以配置多个environment子节点, 怎么理解呢?

  假如我们系统的开发环境和正式环境所用的数据库不一样(这是肯定的), 那么可以设置两个environment, 两个id分别对应开发环境(dev)和正式环境(final),那么通过配置environments的default属性就能选择对应的environment了, 例如,我将environments的deault属性的值配置为dev, 那么就会选择dev的environment。 至于这个是怎么实现的, 下面源码就会讲。

  好啦,上面简单给大家介绍了一下properties 和 environments 的配置, 接下来就正式开始看源码了:

  上次我们说过mybatis 是通过XMLConfigBuilder这个类在解析mybatis配置文件的,那么本次就接着看看XMLConfigBuilder对于properties和environments的解析:

XMLConfigBuilder:

  1 public class XMLConfigBuilder extends BaseBuilder {  
  2   
  3     private boolean parsed;  
  4     //xml解析器  
  5     private XPathParser parser;  
  6     private String environment;  
  7     
  8     //上次说到这个方法是在解析mybatis配置文件中能配置的元素节点  
  9     //今天首先要看的就是properties节点和environments节点 
  10     private void parseConfiguration(XNode root) { 
  11         try { 
  12           //解析properties元素 
  13           propertiesElement(root.evalNode("properties")); //issue #117 read properties first 
  14           typeAliasesElement(root.evalNode("typeAliases")); 
  15           pluginElement(root.evalNode("plugins")); 
  16           objectFactoryElement(root.evalNode("objectFactory")); 
  17           objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); 
  18           settingsElement(root.evalNode("settings")); 
  19           //解析environments元素 
  20           environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631 
  21           databaseIdProviderElement(root.evalNode("databaseIdProvider")); 
  22           typeHandlerElement(root.evalNode("typeHandlers")); 
  23           mapperElement(root.evalNode("mappers")); 
  24         } catch (Exception e) { 
  25           throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); 
  26         } 
  27     } 
  28    
  29      
  30     //下面就看看解析properties的具体方法 
  31     private void propertiesElement(XNode context) throws Exception { 
  32         if (context != null) { 
  33           //将子节点的 name 以及value属性set进properties对象 
  34           //这儿可以注意一下顺序,xml配置优先, 外部指定properties配置其次 
  35           Properties defaults = context.getChildrenAsProperties(); 
  36           //获取properties节点上 resource属性的值 
  37           String resource = context.getStringAttribute("resource"); 
  38           //获取properties节点上 url属性的值, resource和url不能同时配置 
  39           String url = context.getStringAttribute("url"); 
  40           if (resource != null && url != null) { 
  41             throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other."); 
  42           } 
  43           //把解析出的properties文件set进Properties对象 
  44           if (resource != null) { 
  45             defaults.putAll(Resources.getResourceAsProperties(resource)); 
  46           } else if (url != null) { 
  47             defaults.putAll(Resources.getUrlAsProperties(url)); 
  48           } 
  49           //将configuration对象中已配置的Properties属性与刚刚解析的融合 
  50           //configuration这个对象会装载所解析mybatis配置文件的所有节点元素,以后也会频频提到这个对象 
  51           //既然configuration对象用有一系列的get/set方法, 那是否就标志着我们可以使用java代码直接配置? 
 52           //答案是肯定的, 不过使用配置文件进行配置,优势不言而喻 
 53           Properties vars = configuration.getVariables(); 
 54           if (vars != null) { 
 55             defaults.putAll(vars); 
 56           } 
 57           //把装有解析配置propertis对象set进解析器, 因为后面可能会用到 
 58           parser.setVariables(defaults); 
 59           //set进configuration对象 
 60           configuration.setVariables(defaults); 
 61         } 
 62     } 
 63      
 64     //下面再看看解析enviroments元素节点的方法 
 65     private void environmentsElement(XNode context) throws Exception { 
 66         if (context != null) { 
 67             if (environment == null) { 
 68                 //解析environments节点的default属性的值 
 69                 //例如: <environments default="development"> 
 70                 environment = context.getStringAttribute("default"); 
 71             } 
 72             //递归解析environments子节点 
 73             for (XNode child : context.getChildren()) { 
 74                 //<environment id="development">, 只有enviroment节点有id属性,那么这个属性有何作用? 
 75                 //environments 节点下可以拥有多个 environment子节点 
 76                 //类似于这样: <environments default="development"><environment id="development">...</environment><environment id="test">...</environments> 
 77                 //意思就是我们可以对应多个环境,比如开发环境,测试环境等, 由environments的default属性去选择对应的enviroment 
 78                 String id = child.getStringAttribute("id"); 
 79                 //isSpecial就是根据由environments的default属性去选择对应的enviroment 
 80                 if (isSpecifiedEnvironment(id)) { 
 81                     //事务, mybatis有两种:JDBC 和 MANAGED, 配置为JDBC则直接使用JDBC的事务,配置为MANAGED则是将事务托管给容器,  
 82                     TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); 
 83                     //enviroment节点下面就是dataSource节点了,解析dataSource节点(下面会贴出解析dataSource的具体方法) 
 84                     DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); 
 85                     DataSource dataSource = dsFactory.getDataSource(); 
 86                     Environment.Builder environmentBuilder = new Environment.Builder(id) 
 87                           .transactionFactory(txFactory) 
 88                           .dataSource(dataSource); 
 89                     //老规矩,会将dataSource设置进configuration对象 
 90                     configuration.setEnvironment(environmentBuilder.build()); 
 91                 } 
 92             } 
 93         } 
 94     } 
 95      
 96     //下面看看dataSource的解析方法 
 97     private DataSourceFactory dataSourceElement(XNode context) throws Exception { 
 98         if (context != null) { 
 99             //dataSource的连接池
 100             String type = context.getStringAttribute("type");
 101             //子节点 name, value属性set进一个properties对象
 102             Properties props = context.getChildrenAsProperties();
 103             //创建dataSourceFactory
 104             DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
 105             factory.setProperties(props);
 106             return factory;
 107         }
 108         throw new BuilderException("Environment declaration requires a DataSourceFactory.");
 109     } 
110 }
登录后复制


  通过以上对mybatis源码的解读,相信大家对mybatis的配置又有了一个深入的认识。

  还有一个问题, 上面我们看到,在配置dataSource的时候使用了 ${driver} 这种表达式, 这种形式是怎么解析的?其实,是通过PropertyParser这个类解析:

PropertyParser:

/**
 * 这个类解析${}这种形式的表达式 */public class PropertyParser {  public static String parse(String string, Properties variables) {
    VariableTokenHandler handler = new VariableTokenHandler(variables);
    GenericTokenParser parser = new GenericTokenParser("${", "}", handler);    return parser.parse(string);
  }  private static class VariableTokenHandler implements TokenHandler {    private Properties variables;    public VariableTokenHandler(Properties variables) {      this.variables = variables;
    }    public String handleToken(String content) {      if (variables != null && variables.containsKey(content)) {        return variables.getProperty(content);
      }      return "${" + content + "}";
    }
  }
}
登录后复制


好啦,以上就是对于properties 和 environments元素节点的分析,比较重要的都在对于源码的注释中标出。本次文章到此结束,接下来的文章会继续分析其他节点的配置。

 以上就是深入浅出Mybatis系列(三)--配置详解之properties与environments(mybatis源码篇)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1662
14
CakePHP 教程
1418
52
Laravel 教程
1311
25
PHP教程
1261
29
C# 教程
1234
24
iBatis和MyBatis:哪个更适合你? iBatis和MyBatis:哪个更适合你? Feb 19, 2024 pm 04:38 PM

iBatis与MyBatis:你应该选择哪个?简介:随着Java语言的快速发展,许多持久化框架也应运而生。iBatis和MyBatis是两个备受欢迎的持久化框架,它们都提供了一种简单而高效的数据访问解决方案。本文将介绍iBatis和MyBatis的特点和优势,并给出一些具体的代码示例,帮助你选择合适的框架。iBatis简介:iBatis是一个开源的持久化框架

对比分析JPA和MyBatis的功能和性能 对比分析JPA和MyBatis的功能和性能 Feb 19, 2024 pm 05:43 PM

JPA和MyBatis:功能与性能对比分析引言:在Java开发中,持久化框架扮演着非常重要的角色。常见的持久化框架包括JPA(JavaPersistenceAPI)和MyBatis。本文将对这两个框架的功能和性能进行对比分析,并提供具体的代码示例。一、功能对比:JPA:JPA是JavaEE的一部分,提供了一种面向对象的数据持久化解决方案。它通过注解或X

详解MyBatis动态SQL标签中的Set标签功能 详解MyBatis动态SQL标签中的Set标签功能 Feb 26, 2024 pm 07:48 PM

MyBatis动态SQL标签解读:Set标签用法详解MyBatis是一个优秀的持久层框架,它提供了丰富的动态SQL标签,可以灵活地构建数据库操作语句。其中,Set标签是用于生成UPDATE语句中SET子句的标签,在更新操作中非常常用。本文将详细解读MyBatis中Set标签的用法,以及通过具体的代码示例来演示其功能。什么是Set标签Set标签用于MyBati

实现MyBatis中批量删除操作的多种方式 实现MyBatis中批量删除操作的多种方式 Feb 19, 2024 pm 07:31 PM

MyBatis中实现批量删除语句的几种方式,需要具体代码示例近年来,由于数据量的不断增加,批量操作成为了数据库操作的一个重要环节之一。在实际开发中,我们经常需要批量删除数据库中的记录。本文将重点介绍在MyBatis中实现批量删除语句的几种方式,并提供相应的代码示例。使用foreach标签实现批量删除MyBatis提供了foreach标签,可以方便地遍历一个集

MyBatis批量删除语句的使用方法详解 MyBatis批量删除语句的使用方法详解 Feb 20, 2024 am 08:31 AM

MyBatis批量删除语句的使用方法详解,需要具体代码示例引言:MyBatis是一款优秀的持久层框架,提供了丰富的SQL操作功能。在实际项目开发中,经常会遇到需要批量删除数据的情况。本文将详细介绍MyBatis批量删除语句的使用方法,并附上具体的代码示例。使用场景:在数据库中删除大量数据时,逐条执行删除语句效率低下。此时,可以使用MyBatis的批量删除功能

MyBatis缓存机制详解:一文读懂缓存存储原理 MyBatis缓存机制详解:一文读懂缓存存储原理 Feb 23, 2024 pm 04:09 PM

MyBatis缓存机制详解:一文读懂缓存存储原理引言在使用MyBatis进行数据库访问时,缓存是一个非常重要的机制,能够有效减少对数据库的访问,提高系统性能。本文将详细介绍MyBatis的缓存机制,包括缓存的分类、存储原理和具体的代码示例。一、缓存的分类MyBatis的缓存主要分为一级缓存和二级缓存两种。一级缓存一级缓存是SqlSession级别的缓存,当在

MyBatis 一级缓存详解:如何提升数据访问效率? MyBatis 一级缓存详解:如何提升数据访问效率? Feb 23, 2024 pm 08:13 PM

MyBatis一级缓存详解:如何提升数据访问效率?在开发过程中,高效的数据访问一直是程序员们关注的焦点之一。而对于MyBatis这样的持久层框架而言,缓存是提升数据访问效率的关键方法之一。MyBatis提供了一级缓存和二级缓存两种缓存机制,其中一级缓存是默认开启的。本文将详细介绍MyBatis一级缓存的机制,并提供具体的代码示例,帮助读者更好地理

深入理解MyBatis中的批量Insert实现原理 深入理解MyBatis中的批量Insert实现原理 Feb 21, 2024 pm 04:42 PM

MyBatis是一款流行的Java持久层框架,广泛应用于各种Java项目中。其中,批量插入是一个常见的操作,可以有效提升数据库操作的性能。本文将深入探讨MyBatis中的批量Insert实现原理,并结合具体的代码示例进行详细解析。MyBatis中的批量Insert在MyBatis中,批量Insert操作通常使用动态SQL来实现。通过构建一条包含多个插入值的S

See all articles