[英]Strange behavior with different java application export option
I have java server application wich uses many libs (netty, guava, etc). 我有java服务器应用程序,它使用很多库(netty,guava等)。 I always export this application as one single .jar. 我总是将此应用程序导出为单个.jar。 When I run application in Eclipse, I didn't have any problems. 当我在Eclipse中运行应用程序时,我没有任何问题。 But if I start app in console (Windows, or Ubuntu, doesn't matter), I have strange problem: ALL connection processes via sockets last toooo long. 但是,如果我在控制台(Windows或Ubuntu,无关紧要)启动应用程序,我有一个奇怪的问题:通过套接字的所有连接进程持续太长时间。 For example, simple http connection via HttpAsync or others (rabbitmq connection, etc.) lasts 1-2 min. 例如,通过HttpAsync或其他人(rabbitmq连接等)的简单http连接持续1-2分钟。 But after connection completed, data sends/receives fast. 但连接完成后,数据发送/接收速度很快。 I can't figure what the problem. 我无法弄清楚是什么问题。 As mentioned before, I use Eclipse for development. 如前所述,我使用Eclipse进行开发。
As you know, you can export project 3 dif ways (in Eclipse): 如您所知,您可以导出项目3方式(在Eclipse中):
So, when I used 2 option, I had problem. 所以,当我使用2选项时,我遇到了问题。 When I switched to 3d option (all .jars in folder near main .jar), problem was solved. 当我切换到3d选项(main .jar附近的文件夹中的所有.jars)时,问题就解决了。
Generally there are no big difference between 2 and 3 option (in 2 all .jars just inside one jar). 通常情况下,2和3选项之间没有太大区别(2个所有.jars只在一个jar内)。 I thought that it was cause of extra time needed to load new classes in execution time from the jars. 我认为这是从jar开始在执行时加载新类所需的额外时间的原因。 But problem occurs not only at start, but for all new connections. 但问题不仅发生在开始,而且发生在所有新连接上。
Can someone explain this behavior? 有人可以解释这种行为吗?
UPD: Eclipse Luna. UPD: Eclipse Luna。 Doesn't matter what OS I'm using (Windows, or Ubuntu), even doesn't matter what jvm (tried with different Oracle jdk, even tried open jdk). 无论我使用什么操作系统(Windows,或Ubuntu),甚至无关紧要jvm(尝试使用不同的Oracle jdk,甚至尝试打开jdk)。
This all talks about difference in performance when packaging into JAR v/s extracting into JAR & difference in performance when running from Eclipse v/s running from console. 这一切都讨论了在从JAR v / s解压缩到JAR时的性能差异以及从从控制台运行的Eclipse v / s运行时的性能差异。
What it does: 它能做什么:
In this option Eclipse will extract all the classes from the referenced JARs and package into the generated JAR. 在此选项中,Eclipse将从引用的JAR和包中提取所有类到生成的JAR中。
If you open the JAR then you will find that there are NO referenced JARs packaged but all the classes of referenced JARs are arranged as per the package structure and then packaged inside the JAR at root level. 如果打开JAR,那么您会发现没有打包引用的JAR,但所有引用的JAR类都按照包结构排列,然后在根级别打包在JAR中。 This brings the key difference in performance as compared to the "Packaging required libraries into a jar file" where there is additionally cost of runtime parsing and loading of JAR in memory etc.. 与“将所需的包装到jar文件中”相比,这带来了性能上的关键差异,其中还存在运行时解析和在内存中加载JAR等成本。
When exporting as JAR through Eclipse then it is best option if performance is concern. 当通过Eclipse导出为JAR时,如果关注性能,则最好选择。 Also this is scalable option because you can ship this JAR 这也是可扩展的选项,因为您可以发送此JAR
MANIFEST.MF Main thing to note in this file is you main class. MANIFEST.MF这个文件中要注意的主要是你的主要课程。 When you run the JAR you are directly running the class you need. 当您运行JAR时,您将直接运行所需的类。
Main-Class: com.my.jar.TestSSL
What it does: 它能做什么:
In this option Eclipse will: 在这个选项中,Eclipse将:
org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
and you can also see org.eclipse.jdt.internal.jarinjarloader
package into your generated JAR and this package is just under the root directory of the generated JAR. 通过org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
使用Eclipse的JAR加载机制,你也可以在你生成的JAR中看到org.eclipse.jdt.internal.jarinjarloader
包,这个包就在生成的JAR的根目录下。 Now of course this is the additional cost which comes when you choose this option because when you run the JAR then it is not you main class getting executed but JarRsrcLoader
will be executed which will load your main class and other libraries, and all the referenced libraries are packaged. 当然这当你选择这个选项时会产生额外的成本,因为当你运行JAR时,你不是主类被执行,而是执行JarRsrcLoader
,这将加载你的主类和其他库,以及所有引用的库包装好了。 See MANIFEST.MF section below 请参阅下面的MANIFEST.MF部分
MANIFEST.MF Main thing to note in this file is you main class. MANIFEST.MF这个文件中要注意的主要是你的主要课程。 When you run the JAR, JarRsrcLoader
will run and will do further job. 当您运行JAR时, JarRsrcLoader
将运行并将继续工作。
Rsrc-Main-Class: com.cgi.tmi.TestSSL
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
Now for last Eclipse export option - "Copy required libraries into sub folder next to JAR" , I don't think it is a very scalable solution to consider because this imposes your file system dependency, so I would say don't do it. 现在对于最后一个Eclipse导出选项 - “将所需的库复制到JAR旁边的子文件夹” ,我认为这不是一个非常可扩展的解决方案,因为这会强制您的文件系统依赖,所以我想不要这样做。
When you run application from Eclipse then it is quiet similar to 1st export option where Eclipse doesn't need to parse and load JARs at runtime and all. 当你从Eclipse运行应用程序时,它很安静,类似于第一个导出选项,其中Eclipse不需要在运行时解析和加载JAR。
This is however a very trivial point, key is the consideration of Eclipse JAR export option 1 v/s option 2. 然而,这是一个非常简单的观点,关键是考虑Eclipse JAR导出选项1 v / s选项2。
As we don't know the exact structure of your JAR here is a more general explanation (assumed you run your application with java -jar your_app.jar
). 由于我们不知道JAR的确切结构,因此这是一个更一般的解释(假设您使用java -jar your_app.jar
运行应用程序)。
case Copy required libraries into sub folder next to JAR. case 将所需的库复制到JAR旁边的子文件夹中。
your_app.jar
to find a required class 如果需要加载类,则类加载器(在运行时JAR之后)首先检查your_app.jar
以查找所需的类 case Package required libraries into JAR case将所需的库打包到JAR中
your_app.jar
to find a required class 如果需要加载类,则Eclipse类加载器JarRsrcLoader(在运行时JAR之后)首先检查your_app.jar
以查找所需的类 your_app.jar
before the content can be read 如果找不到类,则遍历所有嵌入的JAR文件,这意味着首先需要从your_app.jar
解压缩才能读取内容 If you have a bigger number of hugh embedded library JARs this might lead in a slow down of class loading (but only for the first time a class is loaded by a class loader). 如果你有更多的hugh嵌入式库JAR,这可能会导致类加载速度变慢(但只是第一次类加载器加载一个类)。
You can see the difference in the class loading if you compare the outpout of 如果你比较的是outpout,你可以看到类加载的差异
java -verbose:class -jar your_app_external_library_jars.jar
with 同
java -verbose:class -jar your_app_embedded_library_jars.jar
The performance might be improved by generating an INDEX.LIST
file for each JAR file (eg your_app.jar
and the embedded library JARs). 通过为每个JAR文件(例如your_app.jar
和嵌入式库JAR)生成INDEX.LIST
文件,可以提高性能。
It happens because when you go with "uber jar" approach, some metadata might be lost. 这是因为当你采用“超级罐”方法时,一些元数据可能会丢失。
It's just an example, but if you download this and this , take a look inside the jar. 这只是一个例子,但是如果你下载这个和这个 ,看看罐子里。 There are a few files with the same name in the same META-INF folder. 在同一META-INF文件夹中有一些具有相同名称的文件。
Those files might be important, and when eclipse repackages things for you, he might not be the doing a decent job on merging such files. 这些文件可能很重要,当eclipse为你重新打包时,他可能不会在合并这些文件方面做得不错。
That is what might be happening to you. 这就是你可能会发生的事情。
In the 2nd approach, You have all dependency jars in the main.jar. 在第二种方法中,您在main.jar中拥有所有依赖项jar。 So it won't load any of the dependency jars unless required. 因此除非需要,否则它不会加载任何依赖jar。 Whereas, in case of 3rd option, your main.jar and other dependency jars are independent (unlike 2nd way), and hence gets loaded for connections and is available. 然而,在第3个选项的情况下,你的main.jar和其他依赖jar是独立的(不像第二种方式),因此可以加载连接并且可用。
try adding a log statement or syso by manipulating a dependency jar to see this working. 尝试通过操作依赖jar来添加日志语句或syso以查看此工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.