MyBatis源码 核心配置解析 properties元素
XMLConfigBuilder的parseConfiguration(XNode)方法,用于解析配置文件
XMLConfigBuilder的propertiesElement(XNode)方法,用于解析配置文件的properties标签。
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
//1.读取 <property> 元素的内容
Properties defaults = context.getChildrenAsProperties();
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
//不能同时设置 resource 和 url 属性
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.");
}
//2.读取外部属性文件中的内容
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
//3.读取创建 SqlSessionFactory 对象时,用户传入的 Properties 参数对象
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
//将最终的结果存入Configuration和XPathParser
parser.setVariables(defaults);
configuration.setVariables(defaults);
/*
总结:
1.属性的读取顺序, property 元素先于外部属性文件先于 Properties 参数对象。后存入属性的将覆盖先前存入的同名属性。
因为:Properties 对象存入键值对时,键已存在,用新值覆盖旧值。
优先级:
Properties 参数对象 > 外部属性文件 > properties 元素
2.最终的结果存入了 Configuration 和 XPathParser
*/
}
}
解析 properties 元素时序图

官方对Properties的解释:

Properties的使用:
property元素
resource/url引用外部的properties文件
<properties resource="org/mybatis/example/jdbc.properties">
<property name="username" value="dev_user"/>
<property name="password" value="12345"/>
</properties>
#这是一个外部的 jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3307/micro_message
jdbc.username=root
jdbc.password=root
Properties参数对象
示例:
Properties properties = new Properties();
properties.setProperty("jdbc.username", "admin");
properties.setProperty("jdbc.password", "admin123");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader, properties);
创建 SqlSessionFactory 对象时,可以传入 Properties 参数对象。
public SqlSessionFactory build(Reader reader, Properties properties);
public SqlSessionFactory build(Reader reader, String environment, Properties properties);
public SqlSessionFactory build(InputStream inputStream, Properties properties);
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties);
配置文件中通过 ${} 使用属性
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
MyBatis 源码中与 properties 元素解析相关的几个对象的数据关系:
XMLConfigBuilder BaseBuilder
XPathParser
Configuration
注意:箭头在这里仅表示引用关系。

XNode

public String getStringAttribute(String name) {
return getStringAttribute(name, null);
}
public String getStringAttribute(String name, String def) {
String value = attributes.getProperty(name);
if (value == null) {
return def;
} else {
return value;
}
}
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;
}
public List<XNode> getChildren() {
List<XNode> children = new ArrayList<>();
NodeList nodeList = node.getChildNodes();
if (nodeList != null) {
for (int i = 0, n = nodeList.getLength(); i < n; i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
children.add(new XNode(xpathParser, node, variables));
}
}
}
return children;
}

public XNode(XPathParser xpathParser, Node node, Properties variables) {
this.xpathParser = xpathParser;
this.node = node;
this.name = node.getNodeName();
this.variables = variables;
this.attributes = parseAttributes(node);
this.body = parseBody(node);
}
private Properties parseAttributes(Node n) {
Properties attributes = new Properties();
NamedNodeMap attributeNodes = n.getAttributes();
if (attributeNodes != null) {
for (int i = 0; i < attributeNodes.getLength(); i++) {
Node attribute = attributeNodes.item(i);
String value = PropertyParser.parse(attribute.getNodeValue(), variables);
attributes.put(attribute.getNodeName(), value);
}
}
return attributes;
}
private String parseBody(Node node) {
String data = getBodyData(node);
if (data == null) {
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
data = getBodyData(child);
if (data != null) {
break;
}
}
}
return data;
}
private String getBodyData(Node child) {
if (child.getNodeType() == Node.CDATA_SECTION_NODE
|| child.getNodeType() == Node.TEXT_NODE) {
String data = ((CharacterData) child).getData();
data = PropertyParser.parse(data, variables);
return data;
}
return null;
}
阅读源码 核心思想
修炼功法
按照功法修炼,可以不断突破瓶颈,提升实力。
无功法,难得道。
上层结构
界面,粒度,跟踪数据,这些都是在代码的细节上建造的上层知识结构,这种上层结构是理解和组织的产物,是处于缓慢消退的记忆,只有缓慢消退的记忆才具有价值。
概念性的东西:获取感性的认识,而非严格的定义。
功法残页1:粒度学习。
粒度由大到小才是一种合理的学习顺序。先了解下新类,再去关注新类中新方法的功能,再去关注新类中新方法的功能的实现。关注你需要了解的新类和需要了解的方法,不要看见一个新类,不看完它的方法不罢休。你一上来直奔新类新方法的功能的实现,结果整了一天看了2个方法。整个系统成千上万的方法,看到何年何月。而且没有上层建筑,你就会前学后忘。
目标1. 认识新类:先了解下新的类的基本作用。
目标2. 认识新类的新方法的功能:了解类的方法的功能
了解多个新方法的功能:先掌握认识的类的一个方法的功能,再了解需要了解的方法的功能。
目标3. 理解新方法的实现:认识类的方法的实现
举例:
系统十分复杂,我们通常不可能掌握每个细节。我们应该从大到小的分层次去认识这个复杂的系统。生活中,我们先知道了中国,然后才知道西安,然后知道了西安有个回民街,钟楼,大雁塔。系统中,类就是一个比较大的层次,而类的方法就是比较小的层次。
示例:
/*
分析:
读源码,必然遇到新的类,新的方法。
第1步,认识新类。了解这个类的基本作用。
第2步,认识新类的新方法的功能。大致的理解这个方法的作用,通过自己看实现或看别人的分析。
第3步,认识新类的新方法的实现。搞清楚这个方法的内部实现。
这个XNode中的构造方法涉及了新类:XPathParser Node XNode
认识新类:
1. XPathParser 通过XPath表达式解析xml文档的类。
2. Node 表示xml文档中节点的对象。
3. XNode MyBatis提供的对Node进行封装后对象。
认识新类的方法:XNode的构造方法
把传递的3个参数直接保存了起来。作为自己的状态。
进行处理,得到了3个处理结果,也保存了起来,作为自己的状态。
*/
public XNode(XPathParser xpathParser, Node node, Properties variables) {
this.xpathParser = xpathParser;
this.node = node;
this.name = node.getNodeName();
this.variables = variables;
this.attributes = parseAttributes(node);
this.body = parseBody(node);
}
功法残页2:跟踪数据
程序的核心就是数据,数据的处理逻辑和数据的存储,跟踪你关注的数据,你将会接触到系统内部与这个数据相关的新类和新方法,从而提升对系统的认识。对学习系统的的任务划分提供了一种方式。
这样将对把系统的学习拆分了。现在只需要了解这些与关注数据相关的新类和新方法,就能提升对系统的认识。而不是把一个新类的全部东西都学完也不一定能够提升对系统的认识。
示例:
MyBatis 中 build 方法的3个参数,reader environment properties,跟踪这3个数据。你将会对MyBatis系统有进一步的认识。
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
功法残页3:系统界面
示例: MyBatis 在插件方面,为开发人员提供了哪些东西呢?
MyBatis 为插件提供了 plugins 元素 plugin 元素 property 元素 Interceptor 接口,那么可以认为这是 MyBatis 提供的插件相关的界面。提出界面这个概念,一是为了将系统内部实现和用户操作部分分开。二是为了提供一个角度去认识系统。
个人认为:系统给开发提供的东西叫做这个系统的接口,而用于某个目的一组相关的接口,把这些东西当作系统的提供给开发人员的相关界面。界面,对学习系统的的任务划分提供了一种方式,每次关注系统的一个界面,学习系统的这个界面,获得对系统的认识的提升。
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
MyBatis源码 核心配置解析 properties元素的更多相关文章
- MyBatis 源码分析 - 配置文件解析过程
* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...
- Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(二) 首先了解下sql mapper的动态sql语法 具体的动态sql的 ...
- mybatis源码核心代码
/** * mybatis源码测试类 * @param args * @throws IOException * @see org.apache.ibatis.session.Configuratio ...
- mybatis源码-原来resultMap解析完是这样
目录 1 两个基础类 1.1 列映射类ResultMapping 1.2 结果集映射类ResultMap 2. 解析 2.1 入口函数 2.2 解析流程 2.3 获取 id 2.4 解析结果集的类型 ...
- Mybatis源码解读-配置加载和Mapper的生成
问题 Mybatis四大对象的创建顺序? Mybatis插件的执行顺序? 工程创建 环境:Mybatis(3.5.9) mybatis-demo,参考官方文档 简单示例 这里只放出main方法的示例, ...
- MyBatis 源码分析——配置信息
MyBatis框架的启动前期需要加载相关的XML配置信息.从官网上我们可以了解到他具有十几个节点.其中笔者认为比较重要的节点是settings节点.properties节点.environments节 ...
- MyBatis 源码分析 - 映射文件解析过程
1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...
- Mybatis源码解读-SpringBoot中配置加载和Mapper的生成
本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...
- Mybatis源码解析-BoundSql
mybatis作为持久层,其操作数据库离不开sql语句.而BoundSql则是其保存Sql语句的对象 前提 针对mybatis的配置文件的节点解析,比如where/if/trim的节点解析可见文章Sp ...
随机推荐
- c语言编译器一个不会报错的陷阱
1, 由于数字1和小写字母L(l)长得特别像,特别是VS默认字体里的,所以 double a; scanf("%1f",&a); double b; scanf(" ...
- Windows下MySQL安装流程,8.0以上版本ROOT密码报错及修改
官网下载MySQL安装后,解压,添加环境变量,以管理员方式运行cmd,运行以下命令 mysqld --initialize --console mysqld -install net start my ...
- HOT SUMMER 每天都是不一样,积极的去感受生活 C#关闭IE相应的窗口 .
window.close(); System.Diagnostics.Process[] myProcesses; myProcesses = System.Diagnostics ...
- gogs私有代码库上传项目
https://blog.csdn.net/zhouxueli32/article/details/80538017 一.上传 在cmd命令里进入该项目 然后依次输入以下命令 git initgit ...
- Prometheus Alertmanager 介绍详解
Prometheus 之 Alertmanager 介绍详解 告警无疑是监控中非常重要的环节,虽然监控数据可视化了,也非常容易观察到运行状态.但我们很难做到时刻盯着监控,所以程序来帮巡检并自动告警,这 ...
- 【Hyper-V】尝试启动选定的虚拟机时出错 32788
错误描述 遇到问题如往常一般搜索了一番(好久没搜索问题了)忽然发现,现在百度文章质量较前几年差太多...怪不得那么多人转搜狗搜索(搜微信文章) PS:有些说是目录权限问题,有些是说虚拟磁盘删了重新加载 ...
- XmlExtensions帮助类
public static class XmlExtensions { static Lazy<XmlWriterSettings> _settings = new Lazy<Xml ...
- ASP.NET MVC IOC 之 Autofac(二)
在上一章节,我们已经知道了再控制器中如何注入以及使用了.这一章,我们重点讲解下,如何在服务层中使用. 我们新定义一个教师类,在服务层中,通过这个教师类服务层,获取学生的年龄.实现在教师类的服务层中调用 ...
- Python基础12
jupyter notebook 快捷键 ”Ctrl + / ” 快速注释/撤销注释.注释整行或者整段代码.
- java 手写 jvm高性能缓存
java 手写 jvm高性能缓存,键值对存储,队列存储,存储超时设置 缓存接口 package com.ws.commons.cache; import java.util.function.Func ...