一句话总结:Maven 的传递依赖不是靠 JAR 文件本身实现的,而是靠 .pom 文件中的元数据。如果你用 mvn install:install-file 安装一个 JAR 却没提供 POM,那它就是一座“断桥”——别人能引用你,但走不到你依赖的库。

在日常开发中,我们经常遇到这样的场景:第三方供应商给了你一个闭源 SDK,只有 .jar 文件,我们都会使用:

mvn install:install-file -Dfile=your-jar.jar -DgroupId=com.yourcompany -DartifactId=your-jar -Dversion=1.0.0 -Dpackaging=jar

看起来一切正常,项目也能编译通过。但一运行就报错:

java.lang.NoClassDefFoundError: com/yourcompany/yourjar/YourClass

奇怪了,你的 JAR 确实依赖它,为什么 Maven 没自动下载?答案就藏在 传递依赖(Transitive Dependencies) 的工作机制里。

什么是传递依赖?假设你的项目 A 依赖库 B,而库 B 又依赖库 C 和 D。在 Maven 中,你不需要显式声明 C 和 D,Maven 会自动把它们加入 classpath —— 这就是传递依赖。

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>32.1.3-jre</version>
</dependency>

Guava 的 POM 文件中声明了对 jsr305、checker-qual 等库的依赖。当你引入 Guava 时,这些依赖会自动传递进来。但有个前提:传递依赖的信息必须存在于该构件对应的 .pom 文件中。

mvn install:自带“导航地图”

当你在一个标准 Maven 项目中运行:

mvn install

Maven 会:编译代码、运行测试、打包生成 target/my-app-1.0.jar;同时将项目的 pom.xml 处理后安装为 my-app-1.0.pom 到本地仓库(如 ~/.m2/repository/com/example/my-app/1.0/);这个 .pom 文件完整保留了 块。因此,当其他项目引用 com.example:my-app:1.0 时,Maven 读取 .pom,自动解析并下载所有传递依赖。

结论:mvn install 安装的构件天然支持传递依赖,因为它附带了完整的“依赖地图”。

现在看这个命令:

mvn install:install-file -Dfile=legacy-utils.jar -DgroupId=com.example -DartifactId=legacy-utils -Dversion=1.0 -Dpackaging=jar

它做了什么?把 legacy-utils.jar 复制到本地仓库;自动生成一个最简 POM 文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>legacy-utils</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>
</project>

注意:没有 <dependencies> !即使这个 JAR 在运行时需要 commons-lang3 或 slf4j-api,Maven 也完全不知道。所以当你在另一个项目中引用它:

<dependency>
  <groupId>com.example</groupId>
  <artifactId>legacy-utils</artifactId>
  <version>1.0</version>
</dependency>

Maven 只会下载 legacy-utils.jar,不会下载它的任何依赖。结果就是运行时 ClassNotFoundException。这就是“不支持传递依赖”的本质:元数据缺失,Maven 无法构建依赖图。

如何修复?解决方法很简单:提供一个包含完整依赖声明的 POM 文件。

步骤 1:创建 legacy-utils-1.0.pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>legacy-utils</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.12.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>2.0.7</version>
    </dependency>
  </dependencies>
</project>

步骤 2:使用 -DpomFile 安装

mvn install:install-file -Dfile=legacy-utils.jar -DpomFile=legacy-utils-1.0.pom

现在,其他项目引用 legacy-utils 时,Maven 会读取这个 POM,自动下载 commons-lang3 和 slf4j-api。传递依赖恢复!