论 Resources.getResourceAsStream("mybatis-config.xml") 是如何寻址的

本文最后更新于:2022年9月9日 下午

单刀直入

大家在学MyBatis的时候肯定用到了Resources.getResourceAsStream("mybatis-config.xml")这行代码
(in SqlSessionUtil

但是有没有想过,为什么这个参数只需要写文件名就能定位呢

  • 有人可能说了:这相对路径,那肯定是在同一个文件夹下嘛

非也,非也

Figure 1

诸君请看,他俩相隔十万八千里

猜想

首先,第一个比较莽撞的猜想,难道是根据resources的文件夹标记定位根目录的吗

非也,非也

去掉标记仍能运行

真相(Maybe)

诸君请看

Figure 2

观察编译后的target文件夹

java文件夹和resources文件夹 合并

统一归并在classes文件夹下

诶,好像有那么点接近真相了,但又没有完全接近…

  • 有华生可能发现盲点了:你这SqlSessionUtil类在utils文件夹下,和mybatis-config.xml也不同级啊,怎么能相对引用

咳咳,这个呢,主要是

上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
ClassLoader[] var3 = classLoader;
int var4 = classLoader.length;
for(int var5 = 0; var5 < var4; ++var5) {
ClassLoader cl = var3[var5];
if (null != cl) {
InputStream returnValue = cl.getResourceAsStream(resource);
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}

这是Resources.getResourceAsStream的深层实现

1
2
3
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}

观察这几行可以发现,在获取文件失败后,会自动加上”/“再进行尝试(非常滴人性化呀)

大家都知道,加上”/“之后,就意味着从根目录进行寻址,也就找到了mybatis-config.xml(我猜根目录是classes)

咳咳,就是这样啦(maybe)

补充

其实这个知识点还可用于mybatis-config.xmlmappers配置

1
2
3
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>

一般来说,每一个映射文件都要这样写入核心配置

但是,这未免太过麻烦,因为每一个映射就要写一行

所以经常写为

1
2
3
<mappers>
<package name="com.mrbeanc.mybatis.mapper"/>
</mappers>

这样就可以把mapper下的所有映射文件自动写入啦

但是这么写是有两个要求的

  1. mapper接口和映射文件所在包一致
  2. mapper接口和映射文件的文件名一致

那么有人就要问了,诶,为什么包要一致啊

你这一个在java文件夹下,一个在resources文件夹下,就算内部包一致,父文件夹也不一致呀

Figure 3

但是结合上面的知识点,可以发现,编译后他俩就会合并

Figure 4

这样一来,他俩就在一个文件夹里了,寻址非常方便

Peace

Ref

017-MyBatis核心配置文件之mappers_哔哩哔哩_bilibili


论 Resources.getResourceAsStream("mybatis-config.xml") 是如何寻址的
https://mrbeancpp.github.io/2022/09/09/论-Resources-getResourceAsStream-mybatis-config-xml-是如何寻址的/
作者
MrBeanC
发布于
2022年9月9日
许可协议