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的使用:

  1. property元素
  2. 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
  1. 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 元素解析相关的几个对象的数据关系:

  1. XMLConfigBuilder BaseBuilder
  2. XPathParser
  3. Configuration

注意:箭头在这里仅表示引用关系。

  1. 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元素的更多相关文章

  1. MyBatis 源码分析 - 配置文件解析过程

    * 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...

  2. Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource

    前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(二) 首先了解下sql mapper的动态sql语法 具体的动态sql的 ...

  3. mybatis源码核心代码

    /** * mybatis源码测试类 * @param args * @throws IOException * @see org.apache.ibatis.session.Configuratio ...

  4. mybatis源码-原来resultMap解析完是这样

    目录 1 两个基础类 1.1 列映射类ResultMapping 1.2 结果集映射类ResultMap 2. 解析 2.1 入口函数 2.2 解析流程 2.3 获取 id 2.4 解析结果集的类型 ...

  5. Mybatis源码解读-配置加载和Mapper的生成

    问题 Mybatis四大对象的创建顺序? Mybatis插件的执行顺序? 工程创建 环境:Mybatis(3.5.9) mybatis-demo,参考官方文档 简单示例 这里只放出main方法的示例, ...

  6. MyBatis 源码分析——配置信息

    MyBatis框架的启动前期需要加载相关的XML配置信息.从官网上我们可以了解到他具有十几个节点.其中笔者认为比较重要的节点是settings节点.properties节点.environments节 ...

  7. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  8. Mybatis源码解读-SpringBoot中配置加载和Mapper的生成

    本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...

  9. Mybatis源码解析-BoundSql

    mybatis作为持久层,其操作数据库离不开sql语句.而BoundSql则是其保存Sql语句的对象 前提 针对mybatis的配置文件的节点解析,比如where/if/trim的节点解析可见文章Sp ...

随机推荐

  1. GreenPlum 大数据平台--基础使用(二)

    连接参数 连接参数 描述 环境变量 应用名称 连接到数据库的应用名称,保存在application_name连接参数中.默认值是psql. $PGAPPNAME 数据库名 用户想要连接的数据库名称.对 ...

  2. BeanCreationException: Error creating bean with name 'classPathFileSystemWatcher'之解决办法

    错误关键信息: BeanCreationException: Error creating bean with name 'classPathFileSystemWatcher' 错误原因:Idea不 ...

  3. Idea必知必会

    声明:此文章根据后续用的越来越多,将会不断补充,之所以以链接的形式,是因为不想在这种使用层面上重复造轮子,写很多重复文章,后续我打算写一些更深入的文章. idea常用操作: idea如何Debug调试 ...

  4. vue系列--vue是如何实现绑定事件

    一.前言 vuejs中的事件绑定,使用<v-on:事件名 = 函数名>来完成的,这里函数名是定义在Vue实例中的methods对象中的,Vue实例可以直接访问其中的方法. 二.事件绑定方式 ...

  5. VS一个奇怪的发布问题

    同事的环境,发布项目时一直提示找不到某dll,在引用及bin里未发现黄色感叹号,后来发现问题是因为项目文件不小心包含了一个外部bin目录,并且该bin目录中的dll删除导致的.

  6. IDEA Rider使用64位IISExpress(3)

    将原来的Programe Files(x86)修改为不带x86的即可.

  7. 《 .NET并发编程实战》阅读指南 - 第7章

    先发表生成URL以印在书里面.等书籍正式出版销售后会公开内容.

  8. 【ELK】7. elasticsearch linux上操作es命令详解

    ========== 1.检查ES节点是否正常启动 curl http://192.168.6.16:9200 正常状态: 非正常状态: 1>确保服务是不是正常启动了,端口用的是哪个 2> ...

  9. 基于.net core 3 和 Orleans 3 的 开发框架:Phenix Framework 7

    Phenix Framework 7 for .net core 3 + Orleans 3 发布地址:https://github.com/phenixiii/Phenix.NET7 2019052 ...

  10. 2019-09-16 PHP CURL CURLOPT参数说明(curl_setopt)

    CURLOPT_RETURNTRANSFER 选项: curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); 如果成功只将结果返回,不自动输出任何内容. 如果失败返回F ...