当前位置: 首页 > news >正文

【Mybatis源码分析】datasource配置${}表达式时是如何被解析的?

核心配置中${}表达式配置的解析

  • 一、核心配置主体
  • 二、核心配置文件中properties是如何被解析的?
  • 三、${} 表达式的解析
  • 四、总结

前提:

核心配置文件是被XMLConfigBuilder 对象进行解析的,configuration 对象是由它父类BaseBuider继承下来的属性。
XMLConfigBuilder 对象解析完配置文件,其信息是被封装在了configuration 对象中,
然后返回,通过SqlSessionFactoryBuilder 去通过build(configuration)方法进行构建SqlSessionFactory对象,
一个数据库是关联一个environment 的,所以是一个sqlSessionFactory 对象对应一个数据库,实际上也对应一个configuration 对象........

一、核心配置主体

配置信息的配置主体先进行阐明:

public Configuration parse() {  if (parsed) {  throw new BuilderException("Each XMLConfigBuilder can only be used once.");  }  parsed = true;  //源码中没有这一句,只有 parseConfiguration(parser.evalNode("/configuration"));  //为了让读者看得更明晰,源码拆分为以下两句  XNode configurationNode = parser.evalNode("/configuration");  parseConfiguration(configurationNode);  return configuration;  
}  
/** * 解析 "/configuration"节点下的子节点信息,然后将解析的结果设置到Configuration对象中 */  
private void parseConfiguration(XNode root) {  try {  //1.首先处理properties 节点     propertiesElement(root.evalNode("properties")); //issue #117 read properties first  //2.处理typeAliases  typeAliasesElement(root.evalNode("typeAliases"));  //3.处理插件  pluginElement(root.evalNode("plugins"));  //4.处理objectFactory  objectFactoryElement(root.evalNode("objectFactory"));  //5.objectWrapperFactory  objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));  //6.settings  settingsElement(root.evalNode("settings"));  //7.处理environments  environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631  //8.database  databaseIdProviderElement(root.evalNode("databaseIdProvider"));  //9.typeHandlers  typeHandlerElement(root.evalNode("typeHandlers"));  //10.mappers  mapperElement(root.evalNode("mappers"));  } catch (Exception e) {  throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);  }  
} 

再看核心配置文件中DTD约束,不难看出其解析顺序和约束是一致的。这些解析出来的结果最后都会封装到configuration对象中。

二、核心配置文件中properties是如何被解析的?

properties的三种配置方式:

  1. 通过property 子标签,进行name<==>value进行配置;
  2. 通过url 属性(外配置文件);
  3. 通过resource 属性(外配置文件)。为契合项目路径,这种方式使用的多。

下面阅读已被吾注解好了的解析properties 的代码

  private void propertiesElement(XNode context) throws Exception {if (context != null) {// 第一种配置方式Properties defaults = context.getChildrenAsProperties();// 第三种利用resource配置String resource = context.getStringAttribute("resource");// 第二种利用url进行配置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.");}// 下面就是分别对resource和url进行判断了if (resource != null) {defaults.putAll(Resources.getResourceAsProperties(resource));} else if (url != null) {defaults.putAll(Resources.getUrlAsProperties(url));}// 这个是看原先有没有对cofiguration中的variables属性赋值// 如果有的话一并加入到defaults这个对象中Properties vars = configuration.getVariables();if (vars != null) {defaults.putAll(vars);}// parser 是一个XPathParser的对象;其中有variable是其中的一个属性// variable 是Properties 对象;// 先对parser 的variable的属性进行赋值,后面用于 对datasource 的配置有用parser.setVariables(defaults);// 解析的结果最后得在configuration中,所以....configuration.setVariables(defaults);}}

这里需要注意的有两点:

  1. SqlSessionBuilder执行build方法的时候,也是可以传一个Properties 对象的,这个对象会在XMLConfigBuilder对象创建的时候赋值给configuration对象,这也就是上面源码那个为什么要去判断一下有没有提前赋值(上面的vars)。
  2. 这里defaults 对象虽然不允许 url 和 resource 属性值都时接受,但是允许接受完 url 或 resource的配置文件后还可以加上第一种配置产生的值,还可以接受 build 传过来的配置,非常的灵活。
  3. Configuration 对象中的set、get方法是对外提供的,当然也可以自行对其进行修改和获取。当然没啥事谁修改这玩意啊。

三、${} 表达式的解析

回到根本,${} 到底是如何解析的呢?

首先需要了解 XNode 类中的 evalNode(String expression) 方法。

在这里插入图片描述
这个 XPathParser 对象都是使用的 XMLConfigBuilder 内的属性 parser 对象。

在这里插入图片描述

variables 解析其他标签也都是共享的,一级传一级的。

所以也就是说解析 datasource 是可以使用共享的 variables 的。

然后就可以看解析的 environmentElement 了,看看。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

解析这个 '${}‘ 的核心代码如下:

/*** 这个类解析${}这种形式的表达式*/
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 + "}";}}
}

四、总结

  1. 解析顺序和DTD约束是一致的;
  2. properties 配置的解析及其三种配置方式,resource和url不可以共存,但使用property子标签配置可以共存;
  3. XMLConfigBuilder 中的 XPathParser 类型对象 parser 属性,在解析过程中一直使用的是同一个,并且所解析的 variables 那个配置也一直在传递;
  4. variables 可以是properties 中所写的配置,也可以是调用SqlSessionBuilder对象中的build方法进行传入;
  5. ${content} 是通过字符串处理的方式和从 variables 查询 content 的方式进行处理的。

相关文章:

【Mybatis源码分析】datasource配置${}表达式时是如何被解析的?

核心配置中${}表达式配置的解析一、核心配置主体二、核心配置文件中properties是如何被解析的&#xff1f;三、${} 表达式的解析四、总结前提&#xff1a; 核心配置文件是被XMLConfigBuilder 对象进行解析的&#xff0c;configuration 对象是由它父类BaseBuider继承下来的属性…...

网络基础概述

1.计算机网络背景 ​ 计算机刚刚发展的时候&#xff0c;是没有网络的&#xff0c;每一台计算机都是相互独立的。后来&#xff0c;人们有了多人协作的需求&#xff0c;人们就想办法把多台计算机用“线”连接起来&#xff0c;实现数据共享。后来&#xff0c;连接到一起的电脑越来…...

微搭使用笔记(四) 通过循环展示组件+json配置生成表单及数据获取

背景及整体思路 上篇文章我们通过微搭提供的数据模型完成了问卷表单页面的创建和数据采集&#xff0c;相对来说除了数据模型配置略显复杂外其他的倒还算方便。 本文我们通过for循环加上json文件配置的方式实现一个通用表单页面&#xff0c;如果更换了表单只需要替换掉json配置…...

做测试5年,靠业务熟悉吃老本,技术短板暴露,30岁被无情辞退...

朋友跟我诉苦&#xff0c;最近他被公司无情辞退了。测试几年&#xff0c;月薪10k&#xff0c;如今已经30了&#xff0c;接下来不知道该怎么办&#xff0c;让我帮他想想办法... 几年下来&#xff0c;也算是公司的骨干成员&#xff0c;不说有功&#xff0c;但一定无过。公司业务…...

Linux系统安装MySQL8.0版本详细教程【亲测有效】

首先官网下载安装包&#xff1a;https://downloads.mysql.com/archives/community/ 一、上传到安装服务器 二、解压 tar -xvf mysql-8.0.31-linux-glibc2.12-x86_64.tar.xz三、移动位置并重新命名 mv mysql-8.0.31-linux-glibc2.12-x86_64 /usr/local/mysql四、创建mysql用户…...

[论文阅读笔记19]SiamMOT: Siamese Multi-Object Tracking

这是CVPR2021的一篇文章, 是利用SOT的一些思想来进行MOT的运动估计. 文章地址: 文章 代码地址: 代码 0. 摘要 本文提出了一个孪生(Siamese)式的MOT网络, 该网络用来估计帧间目标的运动. 为了探究运动估计对多目标跟踪的影响, 本文提出了两种运动建模方式: 显式和隐式. 本文在…...

unix高级编程-fork和execve

fork和vfork vfork是老的实现方法又很多问题 vfork #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <errno.h> #include <sys/stat.…...

Vue3+Ts+Vite开发插件并发布到npm

依赖版本信息如下&#xff1a; "vue": "^3.2.45""typescript": "~4.7.4""vite": "^4.0.0""less": "^4.1.3""terser": "^5.16.4"npm: 8.1.0node: 16.13.0 目标&#xf…...

CAN TP层函数介绍

如果想使用CAN TP层函数,首先需要在网络节点或测试节点配置页面的Componets组件一栏添加osek_tp.dll文件。路径为:C:\Program Files\Vector CANoe 15\Exec32 至于节点的CAPL程序内需不需要引用这个dll文件,无所谓,可写可不写。但是如果是其他dll,必须在CAPL程序中引用。为…...

Spring架构篇--2.5 远程通信基础Select 源码篇--window--Select.open()

前言&#xff1a;在Socket通信中使用Select 来对NIO 进行实现&#xff0c;那么它们的实现方式是怎样的呢&#xff0c;本文从 Selector.open() 进行第一步的分析&#xff1b; Selector.open() &#xff1a; Selector 类&#xff1a; public static Selector open() throws IOEx…...

WEB静态交互展示【数据mock】

文章目录背景需求分析实现过程1.爬取原有项目数据2.将数据引入项目3.打包收工后记背景 接到公司一个【离谱】的需求&#xff0c;要求把已有的项目做一个演示版本&#xff08;静态文件版本&#xff09;&#xff1b;本人觉得前端、后端搞个容器包&#xff0c;一个演示版本不就有…...

(4)C#传智:分支Switch与循环While(第四天)

一、异常捕获 定义&#xff1a;语法无错&#xff0c;程序因某些原因出现的错误&#xff0c;而不能正常运行。 用try-catch进行捕获。哪行代码可能出现异常&#xff0c;你就踹它一脚。 try { 可能会出现异常的代码; ---- …...

Stable-Baselines 3 部分源代码解读 2 on_policy_algorithm.py

Stable-Baselines 3 部分源代码解读 ./common/on_policy_algorithm.py 前言 阅读PPO相关的源码&#xff0c;了解一下标准库是如何建立PPO算法以及各种tricks的&#xff0c;以便于自己的复现。 在Pycharm里面一直跳转&#xff0c;可以看到PPO类是最终继承于基类&#xff0c;也…...

15. Qt中OPenGL的参数传递问题

1. 说明 在OPenGL中&#xff0c;需要使用GLSL语言来编写着色器的函数&#xff0c;在顶点着色器和片段着色器之间需要参数值的传递&#xff0c;且在CPU中的数据也需要传递到顶点着色器中进行使用。本文简单介绍几种参数传递的方式&#xff1a; &#xff08;本文内容仅个人理解&…...

注意,这本2区SCI期刊最快18天录用,还差一步录用只因犯了这个错

发表案例分享&#xff1a; 2区医学综合类SCI&#xff0c;仅18天录用&#xff0c;录用后28天见刊 2023.02.10 | 见刊 2023.01.13 | Accepted 2023.01.11 | 提交返修稿 2022.12.26 | 提交论文至期刊部系统 录用截图来源&#xff1a;期刊部投稿系统 见刊截图来源&#xff1a…...

Could not find resource jdbc.properties问题的解决

以如下开头的内容&#xff1a; Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The error may exist in SQL Mapper Configuration 出现以上问题是没有在src/main/resources下创建jdbc.prop…...

【面试题】==与equals区别、Hashcode作用、hashcode相同equals()也一定为true吗?泛型特点与好处

文章目录1. 和 equals 的区别是什么&#xff1f;2.Hashcode的作用3. 两个对象的hashCode() 相同&#xff0c; 那么equals()也一定为 true吗&#xff1f;4.泛型常用特点5.使用泛型的好处&#xff1f;1. 和 equals 的区别是什么&#xff1f; “” 对于基本类型和引用类型 的作…...

Flex布局中的flex属性

1.flex-grow&#xff0c;flex-shrink&#xff0c;flex-basis取值含义 flex-grow&#xff1a; 延申性描述。在满足“延申条件”时&#xff0c;flex容器中的项目会按照设置的flex-grow值的比例来延申&#xff0c;占满容器剩余空间。 取值情况&#xff1a; 取负值无效。取0值表示不…...

SpringBoot + Ant Design Pro Vue实现动态路由和菜单的前后端分离框架

Ant Design Pro Vue默认路由和菜单配置是采用中心化的方式&#xff0c;在 router.config.js统一配置和管理&#xff0c;同时也提供了动态获取路由和菜单的解决方案&#xff0c;并将在2.0.3版本中提供&#xff0c;因到目前为止&#xff0c;官方发布的版本为2.0.2&#xff0c;所以…...

robotframework自动化测试环境搭建

环境说明 win10 python版本&#xff1a;3.8.3rc1 安装清单 安装配置 selenium安装 首先检查pip命令是否安装&#xff1a; C:\Users\name>pipUsage:pip <command> [options]Commands:install Install packages.download Do…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...