java 如何在单个不可执行的 jar 中包含所有依赖的 jar?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14083151/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to include all dependent Jars within a single non-executable jar?
提问by B Chawla
I am stuck in a very common problem.
我陷入了一个非常常见的问题。
I am plugging my jar (which has many dependencies on third party vendor) into an application server lib directory. If I just copy my jar along with its dependencies into server lib then server classpath becomes to long and hence server is not able to work. Therefore I want to package this Jar with all its dependencies in a single jar so that server's classpath doesn't become too long. I found on various forums that there is a utility to do this i.e. OneJar. But this utility works on executable jar. In my case, my final jar will not be executable.
我将我的 jar(它对第三方供应商有很多依赖)插入到应用程序服务器 lib 目录中。如果我只是将我的 jar 及其依赖项复制到服务器库中,那么服务器类路径就会变得很长,因此服务器无法工作。因此,我想将此 Jar 及其所有依赖项打包在一个 jar 中,以便服务器的类路径不会变得太长。我在各种论坛上发现有一个实用程序可以做到这一点,即 OneJar。但此实用程序适用于可执行 jar。就我而言,我的最终 jar 将无法执行。
Also I tried ZIPFileSetGroup utility provided by ANT but that is causing security issues with Manifest file.
我还尝试了 ANT 提供的 ZIPFileSetGroup 实用程序,但这会导致 Manifest 文件出现安全问题。
Can you please help me in resolving this issue?
你能帮我解决这个问题吗?
Thanks!
谢谢!
回答by Logan
If you use Maven to build, you can use the maven dependency plugin and use the copy-dependency task. It will copy all dependencies into your jar file when it creates it.
如果使用Maven构建,可以使用maven依赖插件,使用copy-dependency任务。它会在创建它时将所有依赖项复制到您的 jar 文件中。
If you manually add the jars to your jar file, then you need to make sure your jar file has a Manifest.mf file in it and specify the main class and classpath inside of that.
如果您手动将 jar 添加到您的 jar 文件中,那么您需要确保您的 jar 文件中有一个 Manifest.mf 文件并在其中指定主类和类路径。
Manifest-Version: 1.0
Main-Class: com.mypackage.MainClass
Class-Path: my.jar log4j.jar
Another option may be to build an .ear file, that is usually how you see enterprise apps or a .war file for web apps when they package specific jar files with them. It sounds like you are using a server, so one of those formats may be a better fit for you.
另一种选择可能是构建一个 .ear 文件,这通常是您在企业应用程序或 Web 应用程序的 .war 文件与它们打包特定 jar 文件时看到的方式。听起来您正在使用服务器,因此其中一种格式可能更适合您。
回答by Ian Roberts
When you say
当你说
child process picks up classpath from server/lib directory
子进程从 server/lib 目录中选取类路径
is this a process that is under your control? If the parent process were to specify the classpath just as
这是一个在你控制之下的过程吗?如果父进程要指定类路径,就像
server/lib/*
(i.e. a literal *
) then the target java
process will enumerate the jar files in the lib
directory itself - they do not all need to be named on the classpath.
(即文字*
)然后目标java
进程将枚举lib
目录本身中的 jar 文件- 它们不需要都在类路径上命名。
But if the parent process is explicitly enumerating server/lib/*.jar
to build the -cp
value then you could take advantage of the fact that the Class-Path
in a JAR manifest takes effect even if a JAR is not "executable". You could use a stanza like this to create a manifest-only JAR file
但是,如果父进程显式枚举server/lib/*.jar
以构建-cp
值,那么Class-Path
即使 JAR 不是“可执行的”,您也可以利用JAR 清单中的 生效这一事实。您可以使用这样的节来创建仅清单 JAR 文件
<!-- location of your 300 dependency JAR files, file1.jar ... file300.jar -->
<property name="lib.dir" location="lib" />
<fileset id="dependencies" dir="${lib.dir}" includes="*.jar" />
<pathconvert property="manifest.classpath" dirsep="/" pathsep=" "
refid="dependencies">
<map from="${lib.dir}" to="myapp" />
</pathconvert>
<jar destfile="myapp-manifest.jar">
<manifest>
<attribute name="Class-Path" value="${manifest.classpath}" />
</manifest>
</jar>
This will produce a JAR file named myapp-manifest.jar
whose manifest contains
这将生成一个名为myapp-manifest.jar
的JAR 文件,其清单包含
Class-Path: myapp/file1.jar myapp/file2.jar ... myapp/file300.jar
You put this file into server/lib
and the 300 dependencies into a new directory server/lib/myapp
. Now the generated -cp
will include just one file (myapp-manifest.jar
) but the resulting java process will have all the 300 myapp
JAR files available to it.
你把这个文件server/lib
和 300 个依赖项放到一个新目录中server/lib/myapp
。现在生成的-cp
将只包含一个文件 ( myapp-manifest.jar
),但生成的 java 进程将拥有所有 300 个myapp
JAR 文件。
回答by JasonM1
Using zipgroupfileset
in the jar task in ANT is the easiest approach.
zipgroupfileset
在 ANT 中的 jar 任务中使用是最简单的方法。
<jar destfile="MyApplication.jar" filesetmanifest="mergewithoutmain">
<zipgroupfileset dir="lib" includes="*.jar" />
<!-- other options -->
<manifest>
<attribute name="Main-Class" value="Main.MainClass" />
</manifest>
</jar>
Note the filesetmanifestflag set to mergewithoutmain merges everything but the Main section of the manifests.
请注意,设置为 mergewithoutmain的filesetmanifest标志会合并除清单的 Main 部分之外的所有内容。
Signed jars are causing the SecurityExceptionwhich need to be handled manually. If any classes associated with signed jars verify the signature on the jar as a whole then those will fail at runtime. Digest signatures against a particular file will be added to the manifest without a problem. Since problem is your classpath getting too large you may not be able to bundle all the jars into a single jar but merge most of them making the CLASSPATH manageable.
签名的 jar 导致需要手动处理的SecurityException。如果与签名 jar 相关联的任何类将 jar 上的签名作为一个整体进行验证,那么这些将在运行时失败。针对特定文件的摘要签名将毫无问题地添加到清单中。由于问题是您的类路径变得太大,您可能无法将所有 jar 捆绑到一个 jar 中,但合并其中大部分使 CLASSPATH 可管理。
There is also : http://code.google.com/p/jarjar/
还有:http: //code.google.com/p/jarjar/
Create target directory with all dependent jars. Next move 10 jars into a temp directory and keep moving the jars in batches of 10 and each time try to create the single jar from that group. When you get the security exception you can isolate which one is causing the problem. Try divide-and-conquer approach. If you have 300 jars then only have to do this 30 times.
使用所有依赖的 jar 创建目标目录。接下来将 10 个罐子移动到一个临时目录中,并继续以 10 个为一组移动罐子,每次尝试从该组创建单个罐子。当您获得安全异常时,您可以隔离导致问题的原因。尝试分而治之的方法。如果您有 300 个罐子,那么只需执行 30 次即可。