Java接口包叫 mapper,XML目录也叫 mapper,会导致 Classpath 冲突吗?

27 阅读2分钟

本文章由 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 会把 javaresources 下的内容合并拷贝到 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,但在文件系统中,它们处于完全不同的层级,互不干扰,就像“北京的朝阳区”和“长春的朝阳区”一样,虽然名字一样,但地理位置完全不同。