Shadow 9 迎来了重要更新,它使用了 Kotlin 进行完全重写,解决了之前版本遗留的一系列问题,并带来了性能和可维护性的显著提升。 Shadow Gradle Plugin 本身是一个用于 Gradle 平台的插件,主要功能是创建包含所有依赖的 "fat JAR" (或称 uber-jar),是 Maven Shade Plugin 的一个强大替代品。
Shadow 的核心优势
Shadow 插件主要解决两大核心问题:
- 创建可执行的 JAR 包 :这是部署应用程序时的主要场景。Shadow 可以将你的应用代码以及所有依赖的库文件打包成一个单一的、可执行的 JAR 文件。这个 JAR 文件不包含 JRE,因此目标系统上需要有 Java 运行环境。你可以通过简单的命令
java -jar your-app-all.jar
来运行你的应用。 - 为库打包和重定位依赖:这是库作者面临的典型场景。当你的库依赖了某个第三方库(例如 Guava 或 ASM),而使用你的库的应用又依赖了同一个库的不同版本时,就可能产生类路径冲突 (classpath conflicts)。Shadow 能够重命名(重定位)你的库所依赖的包名,从而避免这种冲突。
Shadow 9 的主要变化
- Kotlin 重写:整个插件使用 Kotlin 进行了重写,带来了更好的性能和可维护性。
- 最低要求:需要 Gradle 8.11+ 和 Java 11+。
- 插件 ID 变更 :插件 ID 从
com.github.johnrengelman.shadow
变更为com.gradleup.shadow
。 - 默认
duplicatesStrategy
变更 :默认的重复文件处理策略从EXCLUDE
变为了INCLUDE
。这意味着默认情况下,最后遇到的同名文件会覆盖之前的文件。
快速上手
你可以通过 plugins
代码块来应用 Shadow 插件。
kotlin
plugins {
java
id("com.gradleup.shadow") version "<最新版本>"
}
注意 : 请将
<最新版本>
替换为当前最新的 Shadow 插件版本。你可以在 Gradle Plugin Portal 上找到最新版本。
应用插件后,Shadow 会自动配置以下内容:
- 添加一个名为
shadowJar
的ShadowJar
类型的 Task。 - 配置
shadowJar
任务以包含main
sourceSet 的所有源码和runtimeClasspath
configuration 的所有依赖。 - 为
shadowJar
生成的 JAR 文件添加all
作为classifier
,例如my-app-1.0-all.jar
。 - 自动从标准的
jar
任务中继承 Manifest 配置。 - 自动排除 JAR 索引和签名文件。
简单使用示例
示例 1: 创建一个可执行的 Fat JAR
假设你有一个使用了 application
插件的 Java 或 Kotlin 项目。
kotlin
plugins {
application
id("com.gradleup.shadow")
}
application {
mainClass = "com.example.Main"
}
// shadowJar 任务会自动从 application 插件中获取 mainClass 配置
// 并将其设置到 MANIFEST.MF 文件中
配置完成后,运行 ./gradlew shadowJar
即可在 build/libs
目录下生成一个名为 <项目名>-<版本号>-all.jar
的 fat JAR 文件。
你可以通过 java -jar build/libs/your-app-1.0-all.jar
来直接运行它。
或者,你也可以执行 ./gradlew installShadowDist
或者 ./gradlew shadowDistZip
用来生成包含 wrapper 和 JAR 的可执行文件。
示例 2: 在库中重定位包名以避免冲突
这是一个非常实用的功能,特别是对于库的开发者。
kotlin
plugins {
java
id("com.gradleup.shadow")
}
dependencies {
implementation("com.google.guava:guava:31.1-jre")
}
tasks.shadowJar {
// 重定位 Guava 的包名
relocate("com.google.common", "shadow.com.google.common")
}
在上面的例子中,所有 com.google.common
包下的类,在打包后的 JAR 文件中都会被移动到 shadow.com.google.common
包下,并且所有对这些类的引用也会被自动修改。
示例 3: 合并 Service Descriptor 文件
Java 的 ServiceLoader 机制依赖于 META-INF/services/
目录下的服务定义文件。当多个依赖包含同名的服务文件时,你需要将它们合并。
kotlin
tasks.shadowJar {
mergeServiceFiles()
}
这会自动合并所有在 META-INF/services
目录下的同名文件。
总结
Shadow Gradle Plugin 9 通过其强大的功能和现在更为现代化的代码基础,为 Gradle 用户提供了一个创建 fat JAR 和管理复杂依赖场景的优秀解决方案。无论你是需要部署一个独立的应用,还是希望创建一个健壮、无依赖冲突的库,Shadow 都是一个值得考虑的工具。更多用例和说明,请参照: