java - 不同 Java 应用程序导出选项的奇怪行为

标签 java eclipse maven jar jvm

我有一个 java 服务器应用程序,它使用许多库(netty、 Guava 等)。我总是将此应用程序导出为一个 .jar。当我在 Eclipse 中运行应用程序时,我没有遇到任何问题。但是,如果我在控制台(Windows 或 Ubuntu,无关紧要)中启动应用程序,我会遇到一个奇怪的问题:所有通过套接字进行的连接进程持续时间太长。例如,通过 HttpAsync 或其他方式(rabbitmq 连接等)的简单 http 连接持续 1-2 分钟。但是连接完成后,数据发送/接收速度很快。我不知道是什么问题。如前所述,我使用 Eclipse 进行开发。

如您所知,您可以通过 3 种不同的方式导出项目(在 Eclipse 中):

  1. 将所需的库提取到 JAR 中。
  2. 将所需的库打包到 JAR 中。
  3. 将所需的库复制到 JAR 旁边的子文件夹中。

所以,当我使用 2 选项时,我遇到了问题。当我切换到 3d 选项时(主 .jar 附近文件夹中的所有 .jars),问题就解决了。

通常 2 和 3 选项之间没有太大区别(在 2 中,所有 .jars 都在一个 jar 中)。我认为这是在执行时从 jars 加载新类需要额外时间的原因。但问题不仅出现在开始时,而且出现在所有新连接上。

有人可以解释这种行为吗?

更新: eclipse 月神。与我使用的操作系统(Windows 或 Ubuntu)无关,甚至与 jvm 无关(尝试使用不同的 Oracle jdk,甚至尝试打开 jdk)。

最佳答案

这都是关于打包到 JAR 与提取到 JAR 时的性能差异以及从 Eclipse 运行与从控制台运行时的性能差异。

打包到 JAR 与提取到 JAR 时的性能差异:

将所需的库提取到 JAR 中:

它的作用:
在此选项中,Eclipse 将从引用的 JAR 中提取所有类并打包到生成的 JAR 中。

如果你打开 JAR,你会发现没有引用的 JAR 被打包,但是引用的 JAR 的所有类都按照包结构排列,然后在根级别打包到 JAR 中。与“将所需的库打包到 jar 文件中” 相比,这带来了性能上的关键差异,在后者中存在运行时解析和将 JAR 加载到内存等的额外成本。

当通过 Eclipse 导出为 JAR 时,如果关注性能,这是最佳选择。这也是可扩展的选项,因为您可以发送此 JAR

MANIFEST.MF 此文件中要注意的主要内容是您的主类。当您运行 JAR 时,您将直接运行所需的类。

Main-Class: com.my.jar.TestSSL


将需要的库打包成JAR:

它的作用:
在此选项中,Eclipse 将:

  • 将所有引用的 JAR 打包到生成的 JAR 中。
  • 通过org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader使用Eclipse的JAR加载机制,也可以看到org.eclipse.jdt.internal.jarinjarloader打包成你生成的 JAR 和这个包就在生成的 JAR 的根目录下。

现在当然这是您选择此选项时产生的额外成本,因为当您运行 JAR 时,执行的不是您的主类,而是将执行 JarRsrcLoader 以加载您的主类类和其他库,所有引用的库都打包了。请参阅下面的 MANIFEST.MF 部分

MANIFEST.MF 此文件中要注意的主要内容是您的主类。当您运行 JAR 时,JarRsrcLoader 将运行并做进一步的工作。

Rsrc-Main-Class: com.cgi.tmi.TestSSL
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader


现在对于最后一个 Eclipse 导出选项 - “将所需的库复制到 JAR 旁边的子文件夹中”,我认为这不是一个值得考虑的非常可扩展的解决方案,因为这会强加你的文件系统依赖性,所以我会说不要这样做。

从 Eclipse 运行与从控制台运行时的性能差异:

当您从 Eclipse 运行应用程序时,它与第一个导出选项类似,其中 Eclipse 不需要在运行时解析和加载 JAR。
然而,这是一个非常微不足道的问题,关键是要考虑 Eclipse JAR 导出选项 1 与选项 2。


最后的话:

  • 使用“Extract required libraries into JAR”来导出 JAR,您将看到显着的性能提升。
    • 从控制台运行时套接字连接持续很长时间的可能性很小,因为 JVM 运行的代码与从 Eclipse 和控制台运行时的性能相同或相当(考虑到两种情况下的 Java 版本相同)。您可能会因为打包的 JAR 性能而感到不适。尝试提取 JAR,你应该没问题。
  • 另外,请考虑您正在执行的日志记录量。运行时,根据配置,Eclipse 可能会屏蔽大量日志记录,从而节省您的 i/o 时间。
  • 明白怎么做 classes are accessed from JAR class path ,这就像您从 JAR 中引用类时的额外计算成本。

关于java - 不同 Java 应用程序导出选项的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32495781/

相关文章:

java - 当包在 pom.xml 中列为依赖项时,为什么我收到 ClassNotFoundException

Maven 使用三叶草插件运行两次单元测试

java - 如何从其他maven模块获取资源文件夹(文件)?

java - 从 Java 使用 sqlite 获取最后插入的 id 的最佳方法是什么?

java - Android 中的 Uri 字符串不缓存

java - Subclipse 无法重命名文件 (OS X)

java - 如何在Eclipse中检查项目内的所有文件是否已保存?

java - LibGDX - 如何保存生成的 FreeType 字体

java - 将 Map<A, B> 转换为 List< Pair<A,B>> - 在 A、B 是类的情况下,这是最有效的吗?

java - 如何实现具有2个独立键的 map ?