本文章由 Gemini 3.0 pro 生成
前言
作为一个 Java 后端刚入门的开发者,最近在配置 Spring Boot + MyBatis 时遇到了一个让人纠结的问题。
我们通常会在 application.yml 中配置 MyBatis 的 XML 文件路径:
mybatis:
# 也就是去 resources 下找 mapper 文件夹
mapper-locations: classpath:mapper/*Mapper.xml
但是,我的 Java 接口(DAO 层)存放的包名通常也是 mapper,比如 com.example.project.mapper。
这时候我就产生了一个疑问:
Java 代码里有一个
mapper包,resources 目录下又建了一个mapper文件夹。 这两个都叫mapper,编译后放到classpath下,会不会重名?会不会冲突?
经过一番研究和实验,我终于搞懂了其中的原理,这里记录一下,希望能帮到同样的初学者。
1. 结论先行
答案是:完全不会冲突,也不会重名。
你可以放心地在 resources 下新建一个 mapper 文件夹来放 XML,同时在 Java 代码里使用 ...mapper 的包名。
核心原因: Java 的包名(Package)在编译后会变成多级目录,而 resources 下的文件夹通常在根目录。它们在文件系统中的“层级”完全不同。
2. 深入图解:源文件 vs 编译后
要理解为什么不冲突,我们需要看一看项目从“源码”变成“字节码(Class文件)”的过程。
2.1 开发时的目录结构 (Source)
在 IDEA 中,我们看到的结构通常是这样的:
src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ └── mapper <-- ① 这里存放 UserMapper.java 接口
│ └── resources
│ └── mapper <-- ② 这里存放 UserMapper.xml 映射文件
看起来好像有两个 mapper,但请注意 ① 号 mapper 前面有一长串包名。
2.2 编译后的目录结构 (Classpath)
当我们运行 mvn compile 或者启动项目时,Maven 会把 java 和 resources 下的内容合并拷贝到 target/classes 目录下(这个目录就是所谓的 Classpath 根路径)。
编译后的真实结构是这样的:
target/classes (Classpath 根)
├── com
│ └── example
│ └── demo
│ └── mapper <-- ① Java接口编译后的 class 文件在这里
│ └── UserMapper.class
│
└── mapper <-- ② XML 文件在这里
└── UserMapper.xml
2.3 真相大白
- Java 接口的家:它的完整地址是
com/example/demo/mapper。它是“根目录”的曾孙子。 - XML 文件的家:它的完整地址是
mapper。它是“根目录”的亲儿子。
虽然它们简称都叫 mapper,但在文件系统中,它们处于完全不同的层级,互不干扰,就像“北京的朝阳区”和“长春的朝阳区”一样,虽然名字一样,但地理位置完全不同。