[英]Strange behavior with different java application export option
我有java服务器应用程序,它使用很多库(netty,guava等)。 我总是将此应用程序导出为单个.jar。 当我在Eclipse中运行应用程序时,我没有任何问题。 但是,如果我在控制台(Windows或Ubuntu,无关紧要)启动应用程序,我有一个奇怪的问题:通过套接字的所有连接进程持续太长时间。 例如,通过HttpAsync或其他人(rabbitmq连接等)的简单http连接持续1-2分钟。 但连接完成后,数据发送/接收速度很快。 我无法弄清楚是什么问题。 如前所述,我使用Eclipse进行开发。
如您所知,您可以导出项目3方式(在Eclipse中):
所以,当我使用2选项时,我遇到了问题。 当我切换到3d选项(main .jar附近的文件夹中的所有.jars)时,问题就解决了。
通常情况下,2和3选项之间没有太大区别(2个所有.jars只在一个jar内)。 我认为这是从jar开始在执行时加载新类所需的额外时间的原因。 但问题不仅发生在开始,而且发生在所有新连接上。
有人可以解释这种行为吗?
UPD: Eclipse Luna。 无论我使用什么操作系统(Windows,或Ubuntu),甚至无关紧要jvm(尝试使用不同的Oracle jdk,甚至尝试打开jdk)。
这一切都讨论了在从JAR v / s解压缩到JAR时的性能差异以及从从控制台运行的Eclipse v / s运行时的性能差异。
它能做什么:
在此选项中,Eclipse将从引用的JAR和包中提取所有类到生成的JAR中。
如果打开JAR,那么您会发现没有打包引用的JAR,但所有引用的JAR类都按照包结构排列,然后在根级别打包在JAR中。 与“将所需的包装到jar文件中”相比,这带来了性能上的关键差异,其中还存在运行时解析和在内存中加载JAR等成本。
当通过Eclipse导出为JAR时,如果关注性能,则最好选择。 这也是可扩展的选项,因为您可以发送此JAR
MANIFEST.MF这个文件中要注意的主要是你的主要课程。 当您运行JAR时,您将直接运行所需的类。
Main-Class: com.my.jar.TestSSL
它能做什么:
在这个选项中,Eclipse将:
org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
使用Eclipse的JAR加载机制,你也可以在你生成的JAR中看到org.eclipse.jdt.internal.jarinjarloader
包,这个包就在生成的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不需要在运行时解析和加载JAR。
然而,这是一个非常简单的观点,关键是考虑Eclipse JAR导出选项1 v / s选项2。
由于我们不知道JAR的确切结构,因此这是一个更一般的解释(假设您使用java -jar your_app.jar
运行应用程序)。
case 将所需的库复制到JAR旁边的子文件夹中。
your_app.jar
以查找所需的类 case将所需的库打包到JAR中
your_app.jar
以查找所需的类 your_app.jar
解压缩才能读取内容 如果你有更多的hugh嵌入式库JAR,这可能会导致类加载速度变慢(但只是第一次类加载器加载一个类)。
如果你比较的是outpout,你可以看到类加载的差异
java -verbose:class -jar your_app_external_library_jars.jar
同
java -verbose:class -jar your_app_embedded_library_jars.jar
通过为每个JAR文件(例如your_app.jar
和嵌入式库JAR)生成INDEX.LIST
文件,可以提高性能。
在第二种方法中,您在main.jar中拥有所有依赖项jar。 因此除非需要,否则它不会加载任何依赖jar。 然而,在第3个选项的情况下,你的main.jar和其他依赖jar是独立的(不像第二种方式),因此可以加载连接并且可用。
尝试通过操作依赖jar来添加日志语句或syso以查看此工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.