
本文旨在解决gradle多模块项目中,如何将主模块及其所有依赖打包成一个可独立运行的“胖jar”(fat jar)文件的问题。通过引入`com.github.johnrengelman.shadow`插件,并配置主类信息,我们可以轻松生成一个包含所有运行时依赖的jar包,从而实现`java -jar`命令的便捷执行,极大地简化了应用程序的部署与分发。
在Gradle项目中,尤其是在采用settings.gradle进行多模块管理的复杂结构中,将一个模块及其所有外部依赖打包成一个可独立运行的JAR文件(通常称为“胖JAR”或“Uber JAR”)是一个常见的需求。默认的jar任务只会打包当前模块的代码,并不会包含其依赖项。这意味着,如果直接运行默认生成的JAR包,应用程序将因缺少必要的库而报错。为了解决这个问题,我们需要一个专门的工具来聚合所有依赖。
核心解决方案:使用Gradle Shadow Jar插件
com.github.johnrengelman.shadow插件,通常被称为Shadow Jar插件,是Gradle生态系统中用于创建包含所有依赖的可执行JAR包的强大工具。它能够将项目及其所有依赖项(包括传递性依赖)打包到一个单一的JAR文件中,同时处理潜在的类名冲突(例如,不同依赖中包含同名文件的情况)。
步骤一:在主模块中应用Shadow Jar插件
首先,你需要在希望生成可执行JAR包的主模块的build.gradle文件中应用Shadow Jar插件。请注意,settings.gradle主要用于定义项目结构和包含子模块,而具体的构建逻辑和插件应用则发生在各个模块的build.gradle文件中。
// 在你的主模块(例如,名为 'app' 的模块)的 build.gradle 文件中
plugins {
id 'java' // 确保应用了Java插件
id 'application' // 可选,但推荐,用于简化主类配置
id 'com.github.johnrengelman.shadow' version '7.1.2' // 应用Shadow Jar插件,请使用最新稳定版本
}
// ... 其他配置,如 group, version, repositories, dependencies 等
// 配置应用程序的主类
application {
// 定义应用程序的入口主类
mainClass = 'jaso92559.app.App' // 替换为你的实际主类路径
}
// 可选:显式配置JAR文件的Manifest,与application块功能有重叠,
// 但在某些情况下可能需要,例如当不使用application插件时。
jar {
manifest {
attributes "Main-Class": "jaso92559.app.App" // 替换为你的实际主类路径
}
}配置说明:
- id 'java': 这是Gradle项目的基本插件,用于构建Java应用程序。
- id 'application': 这是一个方便的插件,它会自动创建一些任务(如run、distZip、distTar)并允许你通过application块配置应用程序的主类。Shadow Jar插件通常能很好地与application插件集成,自动识别mainClass。
- id 'com.github.johnrengelman.shadow' version '7.1.2': 这是核心配置,应用Shadow Jar插件。请务必将version替换为当前最新的稳定版本。
- application.mainClass: 指定了你的应用程序的入口点。这是java -jar命令执行时会调用的类。
- jar.manifest.attributes "Main-Class": 这是一个传统的Java JAR清单文件配置,用于指定JAR包的主类。当使用application插件时,通常不需要手动配置此项,因为application插件会处理它。但作为一种显式配置,它也能确保主类被正确写入。
步骤二:执行Shadow Jar构建任务
在配置完成后,你可以在项目的根目录下(即settings.gradle文件所在的目录)打开命令行终端,执行Shadow Jar插件提供的构建任务:
./gradlew shadowJar
或者,如果你在Windows系统上:
gradlew shadowJar
Gradle将会编译你的代码,解析所有依赖,并将它们一并打包到一个新的JAR文件中。这个过程可能需要一些时间,具体取决于你的项目大小和依赖数量。
步骤三:定位并运行生成的JAR文件
构建成功后,生成的“胖JAR”文件通常位于主模块的build/libs目录下。它的命名规则通常是[模块名]-[版本号]-all.jar,例如app-all.jar。
你可以通过以下命令来运行它:
java -jar app/build/libs/app-all.jar
请将app/build/libs/app-all.jar替换为你的实际文件路径和名称。
注意事项与最佳实践:
- 插件版本管理: 始终使用Shadow Jar插件的最新稳定版本,以获取最新的功能和bug修复。你可以在其GitHub仓库或Gradle Plugin Portal上查找最新版本。
- 多模块项目中的应用: Shadow Jar插件通常只应用于需要作为独立应用程序分发的主模块。对于其他库模块,它们通常不需要生成“胖JAR”,而是作为依赖被主模块引用。
- JAR文件大小: 胖JAR文件会包含所有依赖,因此文件大小会显著增加。在某些场景下,这可能不是最佳选择(例如,Web应用程序通常打包为WAR或EAR,由应用服务器管理依赖)。
- 类名冲突处理: Shadow Jar插件在打包过程中会尝试处理类名冲突(例如,不同的依赖库中包含同名的META-INF/services文件)。它通常会合并或重命名这些资源,但复杂冲突仍需手动干预。
- 与java -cp的区别: 使用java -jar运行胖JAR文件时,JVM会读取JAR包内部的META-INF/MANIFEST.MF文件中的Main-Class属性来启动应用程序。而java -cp(classpath)命令则需要你手动指定所有依赖的路径,这对于包含大量依赖的复杂项目来说非常繁琐,也是使用Shadow Jar插件的主要原因之一。
通过遵循上述步骤和最佳实践,你可以有效地使用Gradle Shadow Jar插件,为你的Java应用程序创建可独立运行、包含所有依赖的JAR包,从而简化应用程序的部署和分发流程。










