为什么 shadowJar minimise() 没有删除所有未使用的依赖项?

Why shadowJar minimise() is not removing all unused dependencies?

我正在尝试从一个项目生成两个不同的 jar,该项目是一个 monorepo,它包括对这个世界上许多伟大事物的依赖,所以不用说我不希望这些可执行 jar 有大尺寸并且会而是让它们只包含他们实际使用的 classes。

我按照此处的说明进行操作 https://imperceptiblethoughts.com/shadow/configuration/minimizing/

为了测试 shadowJar 任务是否真的有效,我创建了一个简单的 Main java 文件,它实际上只使用 java SDK。

public class Main {
    public static void main(String[] args) {
        System.out.println("client");
    }
}

并添加了实际的 shadow jar 任务并将其指向主任务 class

shadowJar {
    archiveBaseName.set('client')
    archiveClassifier.set('')
    archiveVersion.set('0.1')
    minimize()

    manifest {
        attributes 'Main-Class': 'my.package.Main'
    }
}

它正确生成了 uber jar(我能够 运行 它只是用 java -jar ...),但是文件的大小是 10Mb。

然后我生成了一个没有 minimize() 部分的新版本,它是 15Mb。

我这里有什么地方做错了吗? 也许我对这个工具期望太高,而混淆器(尽管设置起来很乏味)是唯一的方法?

由于您没有向我们提供您的构建文件,我只能提供一些一般性建议:

  • 确保这个 Main class 是源代码树中唯一的文件(shadow 不关心 main class 是什么)
  • 确保您的依赖项未标记为 api

正如您自己所说,最小化 有效 。我自己也用 many 依赖项做了一些测试(见下文)。 jar 文件在没有最小化的情况下为 187MB,并且有很多条目我需要启用 zip64。 Shadow 将其最小化为 25MB。

现在,那 25MB 从何而来?根据我在测试中看到的情况,有两种类型的文件会保留:

  • 一般资源文件(实际上 META-INF 文件夹在我的测试用例中是 24MB)
  • package-info.classmodule-info.class(尽管尺寸可能小得多)

无法自动剥离,因为不清楚它们是否被使用。

如果您 100% 确定不需要其中一些文件,您可以 filter 手动将它们从 jar 中取出。虽然我怀疑这样做是否值得。

如果您认为还包含其他文件,您可以提取 Jar(jar 只是一个具有不同扩展名的 zip)并查看其内容。

测试用例

首先,我克隆了 Spring Boot,然后删除了所有不必要的模块(即除 spring-boot-project:spring-bootspring-boot-project:spring-boot-dependenciesspring-boot-project:spring-boot-parent 之外的所有模块)并更改了所有依赖项spring-boot-project:spring-bootimplementation 类型。 然后我删除了当前的源代码并用你的示例替换它 Main class。 添加 shadow 插件后,我得到了一个大小为 187MB 的 jar。当我然后应用 minimize 它只有 25MB。

然后我提取了 Jar 和 运行 一些命令来删除每个 package-infomodule-info 和一般资源文件:

$> find \( \( -not -name "*.class" -or -name "package-info.class" -or -name "module-info.class" \) -and -not -type d \) -delete
$> find -empty -delete

我不知道 Windows 上是否有等效的命令。无论如何,执行上述操作后只剩下少数 class 个文件(144kB!),所以我认为可以说 shadow 正在完成它的工作。