Java 如何使用 Maven 创建具有依赖项的可执行 JAR?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/574594/
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 can I create an executable JAR with dependencies using Maven?
提问by soemirno
I want to package my project in a single executable JAR for distribution.
我想将我的项目打包在单个可执行 JAR 中以进行分发。
How can I make a Maven project package all dependency JARs into my output JAR?
如何让 Maven 项目将所有依赖 JAR 打包到我的输出 JAR 中?
采纳答案by IAdapter
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
and you run it with
然后你运行它
mvn clean compile assembly:single
Compile goal should be added before assembly:single or otherwise the code on your own project is not included.
编译目标应该在程序集之前添加:single 否则不包括您自己项目中的代码。
See more details in comments.
在评论中查看更多详细信息。
Commonly this goal is tied to a build phase to execute automatically. This ensures the JAR is built when executing mvn install
or performing a deployment/release.
通常,此目标与构建阶段相关联以自动执行。这可确保在执行mvn install
或执行部署/发布时构建 JAR 。
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
回答by Matthew McCullough
Taking Unanswered's answer and reformatting it, we have:
以 Unanswered 的答案并重新格式化它,我们有:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
Next, I would recommend making this a natural part of your build, rather than something to call explicitly. To make this a integral part of your build, add this plugin to your pom.xml
and bind it to the package
lifecycle event. However, a gotcha is that you need to call the assembly:single
goal if putting this in your pom.xml, while you would call 'assembly:assembly' if executing it manually from the command line.
接下来,我建议将其作为构建的自然部分,而不是明确调用的内容。要使其成为构建的组成部分,请将此插件添加到您的pom.xml
并将其绑定到package
生命周期事件。然而,一个问题是,assembly:single
如果把它放在 pom.xml 中,你需要调用目标,而如果从命令行手动执行它,你将调用 'assembly:assembly'。
<project>
[...]
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-my-jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
[...]
</build>
</project>
回答by Matthew McCullough
Another option if you really want to repackage the other JARs contents inside your single resultant JAR is the Maven Assembly plugin. It unpacks and then repacks everything into a directory via <unpack>true</unpack>
. Then you'd have a second pass that built it into one massive JAR.
如果您真的想在单个结果 JAR 中重新打包其他 JAR 内容,另一种选择是Maven Assembly 插件。它解包,然后通过<unpack>true</unpack>
. 然后,您将进行第二次传递,将其构建到一个巨大的 JAR 中。
Another option is the OneJar plugin. This performs the above repackaging actions all in one step.
另一种选择是 OneJar 插件。这一步完成了上述重新打包操作。
回答by Matthew Franglen
Ken Liu has it right in my opinion. The maven dependency plugin allows you to expand all the dependencies, which you can then treat as resources. This allows you to include them in the mainartifact. The use of the assembly plugin creates a secondary artifact which can be difficult to modify - in my case I wanted to add custom manifest entries. My pom ended up as:
Ken Liu 在我看来是对的。maven 依赖插件允许您扩展所有依赖项,然后您可以将其视为资源。这允许您将它们包含在主工件中。程序集插件的使用创建了一个难以修改的辅助工件 - 在我的情况下,我想添加自定义清单条目。我的 pom 最终变成了:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-dependencies</id>
<phase>package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
...
<resources>
<resource>
<directory>${basedir}/target/dependency</directory>
<targetPath>/</targetPath>
</resource>
</resources>
</build>
...
</project>
回答by Matthew Franglen
You can use maven-dependency-plugin, but the question was how to create an executable JAR. To do that requires the following alteration to Matthew Franglen's response (btw, using the dependency plugin takes longer to build when starting from a clean target):
您可以使用 maven-dependency-plugin,但问题是如何创建可执行 JAR。要做到这一点,需要对 Matthew Franglen 的响应进行以下更改(顺便说一句,从干净的目标开始时,使用依赖插件需要更长的时间来构建):
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-dependencies</id>
<phase>package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>${basedir}/target/dependency</directory>
</resource>
</resources>
</build>
回答by SRG
I won't answer directly the question as other have already done that before, but I really wonder if it's a good idea to embed all the dependencies in the project's jar itself.
我不会直接回答这个问题,因为其他人之前已经这样做了,但我真的想知道将所有依赖项嵌入项目的 jar 本身是否是个好主意。
I see the point (ease of deployment / usage) but it depends of the use case of your poject (and there may be alternatives (see below)).
我明白这一点(易于部署/使用),但这取决于您的项目的用例(并且可能有替代方案(见下文))。
If you use it fully standalone, why not.
如果您完全独立使用它,为什么不呢。
But if you use your project in other contexts (like in a webapp, or dropped in a folder where other jars are sitting), you may have jar duplicates in your classpath (the ones in the folder, the one in the jars). Maybe not a bid deal but i usually avoid this.
但是,如果您在其他上下文中使用您的项目(例如在 web 应用程序中,或放入其他 jar 所在的文件夹中),您的类路径中可能有 jar 副本(文件夹中的那些,jar 中的一个)。也许不是投标交易,但我通常会避免这种情况。
A good alternative :
一个不错的选择:
- deploy your application as a .zip / .war : the archive contains your project's jar and all dependent jars ;
- use a dynamic classloader mechanism (see Spring, or you can easily do this yourself) to have a single entry point of your project (a single class to start - see the Manifest mechanism on another answer), which will add (dynamically) to the current classpath all the other needed jars.
- 将您的应用程序部署为 .zip / .war :存档包含您项目的 jar 和所有依赖的 jar ;
- 使用动态类加载器机制(请参阅 Spring,或者您可以轻松地自己执行此操作)来拥有项目的单个入口点(要启动的单个类 - 请参阅另一个答案中的清单机制),这将(动态地)添加到当前类路径所有其他需要的罐子。
Like this, with in the end just a manifest and a "special dynamic classloader main", you can start your project with :
像这样,最后只有一个清单和一个“特殊的动态类加载器 main”,您可以使用以下命令开始您的项目:
java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass
回答by kac-ani
It should be like that:
应该是这样的:
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-dependencies</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
Unpacking have to be in generate-resources phase because, if in package phase, will not be included as resources. Try clean package and you'll see.
解包必须在生成资源阶段,因为如果在打包阶段,将不会作为资源包含在内。尝试干净的包装,你会看到。
回答by Mayank
To create an executable JAR from command line itself just run the below command from the project path:
要从命令行本身创建可执行 JAR,只需从项目路径运行以下命令:
mvn assembly:assembly
回答by Vijay Katam
Use the maven-shade-plugin to package all dependencies into one uber-jar. It can also be used to build an executable jar by specifying the main class. After trying to use maven-assembly and maven-jar , I found that this plugin best suited my needs.
使用 maven-shade-plugin 将所有依赖项打包到一个 uber-jar 中。它还可用于通过指定主类来构建可执行 jar。在尝试使用 maven-assembly 和 maven-jar 之后,我发现这个插件最适合我的需求。
I found this plugin particularly useful as it merges content of specific files instead of overwriting them. This is needed when there are resource files that are have the same name across the jars and the plugin tries to package all the resource files
我发现这个插件特别有用,因为它合并特定文件的内容而不是覆盖它们。当 jars 中存在具有相同名称的资源文件并且插件尝试打包所有资源文件时,这是必需的
See example below
请参阅下面的示例
<plugins>
<!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<!-- signed jars-->
<excludes>
<exclude>bouncycastle:bcprov-jdk15</exclude>
</excludes>
</artifactSet>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<!-- Main class -->
<mainClass>com.main.MyMainClass</mainClass>
</transformer>
<!-- Use resource transformers to prevent file overwrites -->
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>properties.properties</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>applicationContext.xml</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/cxf/cxf.extension</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/cxf/bus-extensions.xml</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
回答by André Aronsen
You can use the dependency-plugin to generate all dependencies in a separate directory before the package phase and then include that in the classpath of the manifest:
您可以使用依赖插件在打包阶段之前在单独的目录中生成所有依赖项,然后将其包含在清单的类路径中:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>theMainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
Alternatively use ${project.build.directory}/classes/lib
as OutputDirectory to integrate all jar-files into the main jar, but then you will need to add custom classloading code to load the jars.
或者${project.build.directory}/classes/lib
用作 OutputDirectory 将所有 jar 文件集成到主 jar 中,但是您将需要添加自定义类加载代码来加载 jar。