【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)

不要只听我说,建议你自己动手验证一下,印象会更深:

  1. 找一个 Maven 项目,执行命令 mvn package。
  2. 进入项目的 target 目录。
  3. 找到生成的 .jar 文件。
  4. 把后缀名从 .jar 改成 .zip,然后解压它!

打开解压后的文件夹,你会发现,所谓的“神秘”目录结构,其实就是你 src/main/java 和 src/main/resources 里的东西合并在一起了而已。


结语: 技术没有黑魔法,一切看似复杂的问题,背后往往都是简单的文件操作和路径映射。希望这篇文章能帮你彻底搞懂 Maven 的目录结构,以后的开发之路上少踩几个坑!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐