mybatis源码配置文件解析之一:解析properties标签
mybatis作为日常开发的常用ORM框架,在开发中起着很重要的作用,了解其源码对日常的开发有很大的帮助。源码版本为:3-3.4.x,可执行到github进行下载。
从这篇文章开始逐一分析mybatis的核心配置文件(mybatis-config.xml),今天先来看properties标签的解析过程。
一、概述
在单独使用mybatis的时候,mybatis的核心配置文件(mybatis-config.xml)就显的特别重要,是整个mybatis运行的基础,只有把配置文件中的各个标签正确解析后才可以正确使用mybatis,下面看properties标签的配置,properties标签的作用就是加载properties文件或者property标签,下面看其具体配置,实例如下
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
上面是配置的properties标签的配置,在标签中配置了resource属性和property子标签。下面看具体的解析流程,这里分析properties标签的解析过程,启动流程暂不说,直接看解析的代码。
二、详述
上面,看到了properties标签的配置,下面看其解析方法,这里只粘贴部分代码,下面是parseConfiguration方法的代码,
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
//解析properties标签
propertiesElement(root.evalNode("properties"));
//解析settings标签
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
//解析别名标签,例<typeAlias alias="user" type="cn.com.bean.User"/>
typeAliasesElement(root.evalNode("typeAliases"));
//解析插件标签
pluginElement(root.evalNode("plugins"));
//解析objectFactory标签,此标签的作用是mybatis每次创建结果对象的新实例时都会使用ObjectFactory,如果不设置
//则默认使用DefaultObjectFactory来创建,设置之后使用设置的
objectFactoryElement(root.evalNode("objectFactory"));
//解析objectWrapperFactory标签
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
//解析reflectorFactory标签
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
//解析environments标签
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
//解析<mappers>标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
从上面的代码中可以找到下面的代码,即为解析的代码,
propertiesElement(root.evalNode("properties"));
这个方法就是解析properties标签,下面看具体的解析过程。
1、解析子标签和属性
/**
* 解析mybatis-config.xml文件中的properties标签
*<properties resource="org/mybatis/example/config.properties">
*<property name="username" value="dev_user"/>
*<property name="password" value="F2Fa3!33TYyg"/>
*</properties>
*解析步骤:
*1、解析配置的property标签,放到defaults中;
*2、解析resource或url属性,放到defaults中;
*3、获取configuration中的variables变量值,放到defaults中
* @param context
* @throws Exception
*/
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
//1、读取properties标签中的property标签<property name="" value=""/>
Properties defaults = context.getChildrenAsProperties();
//2、读取properties标签中的resource、url属性
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
//resource和url属性不能同时出现在properties标签中
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
//如果resource不为空,则解析为properties,放到defaults中,由于defaults是key-value结构,所以会覆盖相同key的值
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {//如果url不为空,则解析为properties,放到defaults中,由于defaults是key-value结构,所以会覆盖相同key的值
defaults.putAll(Resources.getUrlAsProperties(url));
}
//3、获得configuration中的variables变量的值,此变量可以通过SqlSessionFactoryBuilder.build()传入properties属性值
Properties vars = configuration.getVariables();
//如果调用build的时候传入了properties属性,放到defaults中
if (vars != null) {
defaults.putAll(vars);
}
//放到parser和configuration对象中
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
从上面的解析过程可以看到,首先解析properties标签的子标签,也就是property标签,通过下面的方法获得,
//1、读取properties标签中的property标签<property name="" value=""/>
Properties defaults = context.getChildrenAsProperties();
解析property标签,并放到Properties对象中。那么是如何防盗Properties对象中的那,在getChildrenAsProperties方法中,
public Properties getChildrenAsProperties() {
Properties properties = new Properties();
for (XNode child : getChildren()) {
String name = child.getStringAttribute("name");
String value = child.getStringAttribute("value");
if (name != null && value != null) {
properties.setProperty(name, value);
}
}
return properties;
}
可以看出是循环property标签,获得其name和value属性,并放入properties对象中。
接着解析properties的resource和url属性,如下
//2、读取properties标签中的resource、url属性
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
分别获得resource和url属性,这里这两个属性都是一个路径。
2、处理属性
下面看这个判断,
//resource和url属性不能同时出现在properties标签中
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
这个判断表明在properties标签中,resource和url属性不能同时出现。
2.1、处理resource和url属性
下面看resource和url属性的处理,这里resource和url两个属性都是代表的一个路径,所以这里肯定是需要读取相应路径下的文件。
//如果resource不为空,则解析为properties,放到defaults中,由于defaults是key-value结构,所以会覆盖相同key的值
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {//如果url不为空,则解析为properties,放到defaults中,由于defaults是key-value结构,所以会覆盖相同key的值
defaults.putAll(Resources.getUrlAsProperties(url));
}
下面看对resource的处理,调用的Resources.getResourceAsProperties(resource))方法,对resource进行处理,
public static Properties getResourceAsProperties(String resource) throws IOException {
Properties props = new Properties();
InputStream in = getResourceAsStream(resource);
props.load(in);
in.close();
return props;
}
从上面的代码可以看出是要转化为InputStream,最后放到Properties对象中,这里加载文件的详细过程,后面再详细分析。
下面看对url的处理,调用Resources.getUrlAsProperties(url)方法,对url进行处理,
public static Properties getUrlAsProperties(String urlString) throws IOException {
Properties props = new Properties();
InputStream in = getUrlAsStream(urlString);
props.load(in);
in.close();
return props;
}
上面的代码依然是把url代表的文件处理成Properties对象。
2.3、处理已添加的Properties
在上面处理完property子标签、resource和url属性后,还进行了下面的处理,即从configuration中获得properties,
//3、获得configuration中的variables变量的值,此变量可以通过SqlSessionFactoryBuilder.build()传入properties属性值
Properties vars = configuration.getVariables();
//如果调用build的时候传入了properties属性,放到defaults中
if (vars != null) {
defaults.putAll(vars);
}
如果configuration中已经存在properties信息,则取出来,放到defaults中。
2.4、放入configuration对象中
经过上面的处理,最后把所有的properties信息放到configuration中,
//放到parser和configuration对象中
parser.setVariables(defaults);
configuration.setVariables(defaults);
把defaults放到了configuration的variables属性中,代表的是整个mybatis环境中所有的properties信息。这个信息可以在mybatis的配置文件中使用${key}使用,比如,${username},则会从configuration的variables中寻找key为username的属性值,并完成自动属性值替换。
三、总结
上面分析了properties标签的解析过程,先解析property标签,然后是resource、url属性,最后是生成SqlSessionFactory的使用调用SqlSessionFactoryBuilder的build方法,传入的properties,从上面的解析过程,可以知道如果存在重复的键,那么最先解析的会被后面解析的覆盖掉,也就是解析过程是:property子标签-->resource-->url-->开发者设置的,那么覆盖过程为:开发者设置的-->url-->resource-->property子标签,优先级最高的为开发者自己设置的properties属性。
原创不易,有不正之处欢迎指正。
mybatis源码配置文件解析之一:解析properties标签的更多相关文章
- mybatis源码配置文件解析之二:解析settings标签
在前边的博客中分析了mybatis解析properties标签,<mybatis源码配置文件解析之一:解析properties标签>.下面来看解析settings标签的过程. 一.概述 在 ...
- mybatis源码配置文件解析之三:解析typeAliases标签
在前边的博客在分析了mybatis解析settings标签,<mybatis源码配置文件解析之二:解析settings标签>.下面来看解析typeAliases标签的过程. 一.概述 在m ...
- mybatis源码配置文件解析之五:解析mappers标签
在上篇博客中分析了plugins标签,<mybatis源码配置文件解析之四:解析plugins标签>,了解了其使用方式及背后的原理.现在来分析<mappers>标签. 一.概述 ...
- mybatis源码配置文件解析之四:解析plugins标签
在前边的博客在分析了mybatis解析typeAliases标签,<mybatis源码配置文件解析之三:解析typeAliases标签>.下面来看解析plugins标签的过程. 一.概述 ...
- mybatis源码配置文件解析之五:解析mappers标签(解析XML映射文件)
在上篇文章中分析了mybatis解析<mappers>标签,<mybatis源码配置文件解析之五:解析mappers标签>重点分析了如何解析<mappers>标签中 ...
- MyBatis 源码分析 - 映射文件解析过程
1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...
- Spring mybatis源码篇章-MybatisDAO文件解析(一)
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-SqlSessionFactory 加载指定的mybatis主文件 Mybatis模板文件,其中的属性 ...
- Spring mybatis源码篇章-MybatisDAO文件解析(二)
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(一) 默认加载mybatis主文件方式 XMLConfigBuilder ...
- mybatis源码配置文件解析之五:解析mappers标签流程图
前面几篇博客分析了mybatis解析mappers标签的过程,主要分为解析package和mapper子标签.补充一张解析的总体过程流程图,画的不好,多多谅解,感谢.
随机推荐
- 软件工程作业0——The Road Not Taken
目录 第一部分:结缘计算机 缘起 四顾 思考 第二部分:在计算机系里学习 挑战 落差 第三部分:未来规划 向前 未来四个月的软工课 项目 内容 这个作业属于 2020春季计算机学院软件工程(罗杰 任健 ...
- Python - 面向对象(二)类方法、静态方法
面向对象的各种方法 静态方法 - @staticmethod class Person(): name = "cool guy" @staticmethod def static( ...
- Python3学习之路~9.4 队列、生产者消费者模型
一 队列queue 当必须在多个线程之间安全地交换信息时,队列在线程编程中特别有用. 队列的作用:1.解耦,使程序直接实现松耦合 2.提高处理效率 列表与队列都是有顺序的,但是他们之间有一个很大的区别 ...
- LeetCode | 707. 设计链表
设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下一个节点的指针/引用.如果要使用双向链表,则还需要一个属性 ...
- MyBatis框架——延迟加载
延迟加载也叫惰性加载或者懒加载,使⽤延迟是为了提⾼程序的运⾏效率,具体是通过尽量少执⾏ SQL 语句来提升效率.Java 程序与数据库的交互频率越低越好,MyBatis 提供的延迟加载功能就可以做到这 ...
- 新文预览 | IoU-aware Single-stage Object Detector for Accurate Localization
论文基于RetinaNet提出了IoU-aware sinage-stage目标检测算法,该算法在regression branch接入IoU predictor head并通过加权分类置信度和IoU ...
- 一款带Web面板的轻量级、高性能内网穿透工具:nps使用教程
说明:内网穿透工具之前已经介绍了不少了,比如Frp.lanproxy.Holer等,现在再介绍个带Web面板的穿透工具nps,之前叫easyProxy,只是改名了而已,该工具是一款使用go语言编写的轻 ...
- 避免自己写的 url 被diss!建议看看这篇RestFul API简明教程!
大家好我是 Guide 哥!这是我的第 210 篇优质原创!这篇文章主要分享了后端程序员必备的 RestFul API 相关的知识. RestFul API 是每个程序员都应该了解并掌握的基本知识,我 ...
- Android适配器
Android适配器 安卓的适配器在我看来是一个非常重要的知识点,面对形式相同但数据源较多的情况时,适配器是一个比较好的解决方法.数据适配器是建立了数据源与控件之间的适配关系,将数据源转换为控件能够显 ...
- 探索学习率设置技巧以提高Keras中模型性能 | 炼丹技巧
学习率是一个控制每次更新模型权重时响应估计误差而调整模型程度的超参数.学习率选取是一项具有挑战性的工作,学习率设置的非常小可能导致训练过程过长甚至训练进程被卡住,而设置的非常大可能会导致过快学习到 ...