当前位置: 首页 > 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 的方式进行处理的。
http://www.lryc.cn/news/16727.html

相关文章:

  • 网络基础概述
  • 微搭使用笔记(四) 通过循环展示组件+json配置生成表单及数据获取
  • 做测试5年,靠业务熟悉吃老本,技术短板暴露,30岁被无情辞退...
  • Linux系统安装MySQL8.0版本详细教程【亲测有效】
  • [论文阅读笔记19]SiamMOT: Siamese Multi-Object Tracking
  • unix高级编程-fork和execve
  • Vue3+Ts+Vite开发插件并发布到npm
  • CAN TP层函数介绍
  • Spring架构篇--2.5 远程通信基础Select 源码篇--window--Select.open()
  • WEB静态交互展示【数据mock】
  • (4)C#传智:分支Switch与循环While(第四天)
  • Stable-Baselines 3 部分源代码解读 2 on_policy_algorithm.py
  • 15. Qt中OPenGL的参数传递问题
  • 注意,这本2区SCI期刊最快18天录用,还差一步录用只因犯了这个错
  • Could not find resource jdbc.properties问题的解决
  • 【面试题】==与equals区别、Hashcode作用、hashcode相同equals()也一定为true吗?泛型特点与好处
  • Flex布局中的flex属性
  • SpringBoot + Ant Design Pro Vue实现动态路由和菜单的前后端分离框架
  • robotframework自动化测试环境搭建
  • 尚硅谷《Redis7》(小白篇)
  • 并非从0开始的c++ day6
  • PMP考前冲刺2.22 | 2023新征程,一举拿证
  • RxJava的订阅过程
  • 【2.22】MySQL、Redis、动态规划
  • 2年手动测试,裸辞后找不到工作怎么办?
  • Leetcode6. N字形变换
  • 将Nginx 核心知识点扒了个底朝天(十)
  • GPU显卡环境配置安装
  • CIMCAI super unmanned intelligent gate container damage detect
  • web概念概述