【Maven避坑】源码去哪了?一文看懂 Maven 工程与打包后的目录映射关系
摘要 :你是否遇到过
FileNotFoundException?是否遇到过 MyBatis 报错Invalid bound statement?很多时候,这并非代码写错了,而是你没搞懂 Maven 打包时把你的文件"搬"到了哪里。本文将通过图解,带你揭开 Maven 打包的"乾坤大挪移"之谜。本文由Gemini 3.0 生成
前言
作为一个 Java 后端新人,在开发过程中,我常会有这样的困惑:
- 我在
src/main/resources下写的application.yml,程序运行起来后到底去哪找它? - 为什么我的 Mapper XML 文件明明在工程里,打包后却不见了?
- 经常听到的 Classpath(类路径),到底指的是哪里?
Maven 遵循"约定优于配置"的原则,但如果我们不了解这个"约定",开发时就会踩坑。今天我们就来拆解一下 Maven 项目从源码 到JAR包的映射关系。
一、 一张图看懂核心映射
Maven 在执行 mvn package 打包时,主要做了一件事:把 src/main 下的Java 代码 和资源文件 ,经过编译和整理,合并到了 JAR 包的根目录下。
请看下面的对比图(这是最核心的知识点):
text
【工程源码目录 (Source)】 【打包后的 JAR 内部目录 (Runtime)】
MyProject
├── src
│ ├── main
│ │ ├── java (Java代码)
│ │ │ └── com
│ │ │ └── demo
│ │ │ └── User.java ---> com/demo/User.class (变成了字节码)
│ │ │
│ │ └── resources (资源文件)
│ │ ├── application.yml -----> application.yml (直接在根目录下!)
│ │ ├── mybatis-config.xml ---> mybatis-config.xml
│ │ └── mapper
│ │ └── UserMapper.xml ---> mapper/UserMapper.xml
│ │
│ └── test (测试代码)
│ └── ... ---> (直接丢弃,不进入最终JAR包)
二、 三大映射规则
理解了上面的图,我们可以总结出 Maven 的三条打包铁律:
1. Java 目录:编译并保持结构
Maven 会调用 javac 将 src/main/java 下的 .java 文件编译成 .class 文件。 重点:包路径(package)会直接转化为文件夹路径。
- 源码:
src/main/java/com/demo/User.java - 打包后:
JAR根/com/demo/User.class
2. Resources 目录:复制并"平铺"
src/main/resources 是资源的根目录 。Maven 会把这个文件夹内部 的所有东西,直接复制到 JAR 包的根目录 下。 重点:它会和编译后的 class 文件混在一起!
- 这就是为什么我们在代码里读取配置文件时(例如
classpath:application.yml),不需要写resources/前缀,因为它就在根目录下。
3. Test 目录:用完即弃
src/test 下的所有代码和资源,仅在 mvn test 阶段生效。它们绝对不会出现在最终生成的 JAR 包里。
- 避坑 :千万不要在生产代码里依赖
src/test下写的工具类。
三、 经典踩坑场景:MyBatis 的 XML 去哪了?
这是初学者最容易遇到的坑。
场景 A:XML 放在 resources 下(推荐 ✅)
如果你把 UserMapper.xml 放在 src/main/resources/mapper/ 下。 根据规则 2,打包后它位于 JAR根/mapper/UserMapper.xml。 一切正常,程序能找到。
场景 B:XML 放在 java 目录下(报错 ❌)
为了方便管理,很多人喜欢把 UserMapper.xml 和 UserMapper.java 接口放在同一个包下,例如 src/main/java/com/demo/mapper/。
后果 : Maven 的默认机制是:在 src/main/java 目录下,只编译 .java 文件,忽略其他所有文件(包括 XML)。 所以,你的 JAR 包里根本没有那个 XML 文件!MyBatis 启动时自然报错。
解决方案 : 如果你非要这么放,必须在 pom.xml 中配置资源过滤,告诉 Maven:"别忽略我的 XML!"
xml
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
四、 所谓的 Classpath 到底是什么?
理解了目录映射,Classpath 的概念就迎刃而解了。
在 Spring 或 Java 中,当我们说 classpath: 时,指的就是 打包后的 JAR 包根目录 (或者在 IDE 开发时,指的是 target/classes 目录)。
classpath:application.yml-> 去 JAR 包根目录找。classpath:com/demo/User.class-> 去 JAR 包根目录下的 com/demo 找。
五、 动手验证(Show me the code)
不要只听我说,建议你自己动手验证一下,印象会更深:
- 找一个 Maven 项目,执行命令
mvn package。 - 进入项目的
target目录。 - 找到生成的
.jar文件。 - 把后缀名从
.jar改成.zip,然后解压它!
打开解压后的文件夹,你会发现,所谓的"神秘"目录结构,其实就是你 src/main/java 和 src/main/resources 里的东西合并在一起了而已。
结语: 技术没有黑魔法,一切看似复杂的问题,背后往往都是简单的文件操作和路径映射。希望这篇文章能帮你彻底搞懂 Maven 的目录结构,以后的开发之路上少踩几个坑!