是否可以将所有jar依赖包装在一个大jar子里?

我知道这不是“最佳实践”,但我可以将所有依赖项包含在一个大jar子里吗?

有一个名为One-Jar的工具可以做你想要的,虽然我会反对它。 表现通常很糟糕。

我的感觉是,称One-Jar的表现糟糕而且糟糕是不公正的。 对于中等大小的应用程序,可以预期启动将花费几秒钟(尽管不会影响JVM启动画面)。 对于大多数环境,除了嵌入式系统之外,几十兆字节的内存开销可以忽略不计。 此外,One-Jar能够自动将一些文件提取到文件系统,从而节省了在我的情况下开发安装程序的需要。

下面是尝试量化One-Jar对我的应用程序引入的性能影响。 它是基于Swing的GUI应用程序,由使用ProGuard 4.5b2混淆的352个类组成。 One-Jar 0.96用于捆绑产生的类,其中包含12MB的库(ODFDOM,Saxon HE,Xerces,Jaxen,VLDocking,Apache Commons等)。 我已经将混淆的jar的性能与One-Jar处理的同一个jar进行了比较。

  • 从JVM开始到main()方法的开始:没有One-Jar的0.5s和One-Jar的1.7s。 从JVM开始到屏幕上应用程序窗口的出现:没有One-Jar的2.3s和带有One-Jar的3.4s。 因此,One-Jar为启动时间增加了1.1秒。
  • One-Jar不会增加屏幕上出现的JVM启动和启动图像之间的延迟(如果通过jar清单实现),因此启动时间的增加对于交互式应用程序来说并不太烦人。
  • 我们讨论的是类加载器,因此除非您广泛使用动态类加载,否则不应对代码执行速度产生任何影响。
  • 查看JVM统计信息(通过jconsole)显示One-Jar’red版本需要更多堆内存。 对于我的应用程序,开销大约为几十MB。 我看到的数据包括16MB vs 40MB,306MB vs 346MB,131MB vs 138MB,这取决于应用程序正在处理的大量用户数据,现在很久以前垃圾收集器已被执行。

上面的时间是通过在从Linux shell启动JVM之前,在main()方法的开头和我的应用程序窗口的windowOpened()事件处理程序中获取时间戳获得的。 测量是在速度不是特别快的D820笔记本电脑上进行的,双核1GHz CPU和运行Ubuntu 8.04的2G或RAM。

希望能帮助到你。

我使用maven程序集插件与jar-with-dependencies描述符

One-JAR在启动时将所有依赖项jar加载到内存中。 这可能听起来非常低效,但自2004年发布以来,没有人向我抱怨它。预加载的可能影响是应用程序的类加载的整体加速,因为类加载器不必重复扫描类路径对于应用程序运行的资源和类:所有内容都是哈希映射的。

构建一个可以按需加载的延迟加载器非常简单:但是我所说的“构建它,测量它,改进它 – 如果有必要的话”,到目前为止还没有必要改进它。

我将在未来的版本中考虑到这一点(或者如果其他人想要解决它,那也会很棒,因为没有非常大的应用程序来衡量,很难知道改变是否有改进)。

如果你想这样做,有一个名为Jar Jar Links的工具可以帮你完成。 从未使用它,但很难忘记这个名字。

  • 您可以解压缩文件并使用命令行重新打包它们

  • 你可以用[uberjar]

  • 你可以使用fatjar

通常你可以,但有时有不寻常的法律技术原因不能。

  • 法律:例如,我们发现在我们想要的时候,我们无法将JavaMail jar文件与我们应用程序的其余部分捆绑在一个大包中,但许可协议说我们必须将它们分开。

  • 技术:另一个问题可能是自定义类加载器在特定jar文件中查找特定资源或类。 这通常发生在应用程序服务器或ESB的容器上下文中。

方法:为此,只需将所有内容解压缩到一个目录中,然后从那里重建jar。 您可能必须调整META-INF文件夹中的某些设置以删除加载其他jar的请求,并处理不同的jar每个都有默认类运行的情况。 有些第三方实用程序可能有所帮助,但除非你知道它们在做什么,否则你要小心。

Eclipse 3.4及更高版本允许您执行此操作。 右键单击您的项目,选择Extract,然后导航到Runnable Jar选项。 选择Next。 选择适当的设置,然后关闭并运行。 此外,我似乎记得使用FatJar(上面提到的)使用的相同或类似的库来实现此function。

为了完整起见 , ProGuard将为您完成此任务,并可选择混淆和缩小JAR。 后一个函数对于创建最终部署JAR特别有用。

还要记住.jar文件是封面下的.zip文件。 您可以使用自己喜欢的拉链工具(重新)打包它们。 在这种情况下,您必须自己处理清单文件。