0

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

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

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

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

并添加了实际的影子 jar 任务并将其指向一个主类

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。

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

4

1 回答 1

1

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

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

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

现在,这些 25MB 是从哪里来的?根据我在测试中看到的情况,有两种类型的文件保留:

  • 一般资源文件(实际上META-INF在我的测试用例中该文件夹为 24MB)
  • package-info.classmodule-info.class(虽然大小可能要小得多)

这些不能自动剥离,因为不清楚它们是否被使用。

如果你 100% 确定你不需要其中的一些文件,你可以手动将它们从你的 jar 中过滤掉。虽然我怀疑这是否值得努力。

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

测试用例

首先,我克隆了Spring Boot,然后删除了所有不必要的模块(即除和spring-boot-project:spring-boot之外的所有模块)并将所有依赖项更改为 type 。然后我删除了当前的源代码并将其替换为您的示例类。添加插件后,我得到了一个大小为 187MB 的 jar。当我申请时,它只有 25MB。spring-boot-project:spring-boot-dependenciesspring-boot-project:spring-boot-parentspring-boot-project:spring-bootimplementationMainshadowminimize

然后我提取了 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 上是否有等效的命令。在任何情况下,执行上述操作只剩下少量的类文件(144kB!),所以我认为可以说影子正在完成它的工作。

于 2022-02-03T12:46:26.153 回答