Java 使用 Maven 在 jar 中包含依赖项
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1729054/
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
Including dependencies in a jar with Maven
提问by racer
Is there a way to force maven(2.0.9) to include all the dependencies in a single jar file?
有没有办法强制 maven(2.0.9) 将所有依赖项包含在单个 jar 文件中?
I have a project the builds into a single jar file. I want the classes from dependencies to be copied into the jar as well.
我有一个项目构建到一个 jar 文件中。我也希望将依赖项中的类复制到 jar 中。
Update:I know that I cant just include a jar file in a jar file. I'm searching for a way to unpack the jars that are specified as dependencies, and package the class files into my jar.
更新:我知道我不能只在 jar 文件中包含一个 jar 文件。我正在寻找一种方法来解压指定为依赖项的 jar,并将类文件打包到我的 jar 中。
采纳答案by John Stauffer
You can do this using the maven-assembly plugin with the "jar-with-dependencies" descriptor. Here's the relevant chunk from one of our pom.xml's that does this:
您可以使用带有“jar-with-dependencies”描述符的 maven-assembly 插件来做到这一点。这是我们的 pom.xml 之一的相关块,它执行此操作:
<build>
<plugins>
<!-- any other plugins -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
回答by Thomas Jung
There's the shade maven plugin. It can be used to package and renamedependencies (to omit dependency problems on the classpath).
有阴影 maven 插件。它可用于打包和重命名依赖项(以省略类路径上的依赖项问题)。
回答by Pascal Thivent
With Maven 2, the right way to do this is to use the Maven2 Assembly Pluginwhich has a pre-defined descriptor filefor this purpose and that you could just use on the command line:
使用 Maven 2,正确的方法是使用Maven2 Assembly Plugin,它具有用于此目的的预定义描述符文件,您可以在命令行上使用它:
mvn assembly:assembly -DdescriptorId=jar-with-dependencies
If you want to make this jar executable, just add the main class to be run to the plugin configuration:
如果要使这个 jar 可执行,只需将要运行的主类添加到插件配置中:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>my.package.to.my.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
If you want to create that assembly as part of the normal build process, you should bind the singleor directory-singlegoal (the assembly
goal should ONLY be run from the command line) to a lifecycle phase (package
makes sense), something like this:
如果您想在正常构建过程中创建该程序集,您应该将单个或目录单个目标(该assembly
目标只能从命令行运行)绑定到生命周期阶段(package
有意义),如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>create-my-bundle</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
...
</configuration>
</execution>
</executions>
</plugin>
Adapt the configuration
element to suit your needs (for example with the manifest stuff as spoken).
调整configuration
元素以满足您的需求(例如,使用清单内容作为口语)。
回答by medopal
回答by lasantha
You can use the newly created jar using a <classifier>
tag.
您可以使用<classifier>
标签使用新创建的 jar 。
<dependencies>
<dependency>
<groupId>your.group.id</groupId>
<artifactId>your.artifact.id</artifactId>
<version>1.0</version>
<type>jar</type>
<classifier>jar-with-dependencies</classifier>
</dependency>
</dependencies>
回答by Rop
If you (like me) dont particularly like the jar-with-dependenciesapproach described above, the maven-solution I prefer is to simply build a WAR-project, even if it is only a stand-alone java application you are building:
如果你(像我一样)不是特别喜欢上面描述的jar-with-dependencies方法,我更喜欢的 maven-solution 是简单地构建一个 WAR 项目,即使它只是你正在构建的一个独立的 java 应用程序:
Make a normal maven jar-project, that will build your jar-file (without the dependencies).
Also, setup a maven war-project (with only an empty src/main/webapp/WEB-INF/web.xmlfile, which will avoid a warning/error in the maven-build), that only has your jar-project as a dependency, and make your jar-project a
<module>
under your war-project. (This war-project is only a simple trick to wrap all your jar-file dependencies into a zip-file.)Build the war-project to produce the war-file.
In the deployment-step, simply rename your .war-file to *.zip and unzip it.
制作一个普通的 Maven jar 项目,它将构建您的 jar 文件(没有依赖项)。
此外,设置一个 maven 战争项目(只有一个空的src/main/webapp/WEB-INF/web.xml文件,这将避免 maven-build 中的警告/错误),它只有你的 jar-project 作为一个依赖项,并使您的 jar-project 成为
<module>
您的 war-project 下的一个。(这个战争项目只是将所有 jar 文件依赖项包装到一个 zip 文件中的简单技巧。)构建战争项目以生成战争文件。
在部署步骤中,只需将您的 .war 文件重命名为 *.zip 并将其解压缩。
You should now have a lib-directory (which you can move where you want it) with your jar and all the dependencies you need to run your application:
您现在应该有一个包含 jar 和运行应用程序所需的所有依赖项的 lib 目录(您可以将其移动到您想要的位置):
java -cp 'path/lib/*' MainClass
(The wildcard in classpath works in Java-6 or higher)
(类路径中的通配符适用于 Java-6 或更高版本)
I think this is both simpler to setup in maven (no need to mess around with the assembly plugin) and also gives you a clearer view of the application-structure (you will see the version-numbers of all dependent jars in plain view, and avoid clogging everything into a single jar-file).
我认为这在 maven 中设置起来更简单(无需弄乱程序集插件),并且还为您提供了更清晰的应用程序结构视图(您将在普通视图中看到所有依赖 jar 的版本号,并且避免将所有内容堵塞到单个 jar 文件中)。
回答by Francois Gergaud
This post may be a bit old, but I also had the same problem recently. The first solution proposed by John Stauffer is a good one, but I had some problems as I am working this spring. The spring's dependency-jars I use have some property files and xml-schemas declaration which share the same paths and names. Although these jars come from the same versions, the jar-with-dependenciesmaven-goal was overwriting theses file with the last file found.
这个帖子可能有点旧,但我最近也遇到了同样的问题。John Stauffer 提出的第一个解决方案是一个很好的解决方案,但我在今年春天工作时遇到了一些问题。我使用的 spring 的依赖 jars 有一些属性文件和 xml-schemas 声明,它们共享相同的路径和名称。尽管这些 jar 来自相同的版本,但jar-with-dependenciesmaven-goal 正在用找到的最后一个文件覆盖这些文件。
In the end, the application was not able to start as the spring jars could not find the correct properties files. In this case the solution propose by Rop have solved my problem.
最后,应用程序无法启动,因为 spring jars 找不到正确的属性文件。在这种情况下,Rop 提出的解决方案解决了我的问题。
Also since then, the spring-boot project now exist. It has a very cool way to manage this problem by providing a maven goal which overload the package goal and provide its own class loader. See spring-boots Reference Guide
也是从那时起,spring-boot 项目就存在了。通过提供一个 maven 目标来重载包目标并提供自己的类加载器,它有一种非常酷的方法来管理这个问题。参见spring-boots 参考指南
回答by André Valenti
http://fiji.sc/Uber-JARprovides an excellent explanation of the alternatives:
http://fiji.sc/Uber-JAR提供了对替代方案的出色解释:
There are three common methods for constructing an uber-JAR:
- Unshaded. Unpack all JAR files, then repack them into a single JAR.
- Pro: Works with Java's default class loader.
- Con: Files present in multiple JAR files with the same path (e.g., META-INF/services/javax.script.ScriptEngineFactory) will overwrite one another, resulting in faulty behavior.
- Tools: Maven Assembly Plugin, Classworlds Uberjar
- Shaded. Same as unshaded, but rename (i.e., "shade") all packages of all dependencies.
- Pro: Works with Java's default class loader. Avoids some (not all) dependency version clashes.
- Con: Files present in multiple JAR files with the same path (e.g., META-INF/services/javax.script.ScriptEngineFactory) will overwrite one another, resulting in faulty behavior.
- Tools: Maven Shade Plugin
- JAR of JARs. The final JAR file contains the other JAR files embedded within.
- Pro: Avoids dependency version clashes. All resource files are preserved.
- Con: Needs to bundle a special "bootstrap" classloader to enable Java to load classes from the wrapped JAR files. Debugging class loader issues becomes more complex.
- Tools: Eclipse JAR File Exporter, One-JAR.
构建 uber-JAR 的常用方法有以下三种:
- 无阴影。解压所有 JAR 文件,然后将它们重新打包成单个 JAR。
- 优点:适用于 Java 的默认类加载器。
- 缺点:存在于具有相同路径的多个 JAR 文件中的文件(例如,META-INF/services/javax.script.ScriptEngineFactory)将相互覆盖,从而导致错误行为。
- 工具:Maven Assembly Plugin、Classworlds Uberjar
- 阴影。与 unshaded 相同,但重命名(即“shade”)所有依赖项的所有包。
- 优点:适用于 Java 的默认类加载器。避免一些(不是全部)依赖版本冲突。
- 缺点:存在于具有相同路径的多个 JAR 文件中的文件(例如,META-INF/services/javax.script.ScriptEngineFactory)将相互覆盖,从而导致错误行为。
- 工具:Maven Shade Plugin
- JAR 的 JAR。最终的 JAR 文件包含嵌入其中的其他 JAR 文件。
- 优点:避免依赖版本冲突。保留所有资源文件。
- 缺点:需要捆绑一个特殊的“引导”类加载器,使 Java 能够从包装的 JAR 文件中加载类。调试类加载器问题变得更加复杂。
- 工具:Eclipse JAR 文件导出器,One-JAR。
回答by Glaucio Southier
My definitive solution on Eclipse Luna and m2eclipse: Custom Classloader (download and add to your project, 5 classes only) :http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org.eclipse.jdt.ui/jar%20in%20jar%20loader/org/eclipse/jdt/internal/jarinjarloader/; this classloader is very best of one-jar classloader and very fast;
我在 Eclipse Luna 和 m2eclipse 上的最终解决方案:自定义类加载器(下载并添加到您的项目,仅 5 个类):http: //git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org。 eclipse.jdt.ui/jar%20in%20jar%20loader/org/eclipse/jdt/internal/jarinjarloader/;这个类加载器是单 jar 类加载器中最好的,而且速度非常快;
<project.mainClass>org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader</project.mainClass>
<project.realMainClass>my.Class</project.realMainClass>
<project.mainClass>org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader</project.mainClass>
<project.realMainClass>my.Class</project.realMainClass>
Edit in JIJConstants "Rsrc-Class-Path" to "Class-Path"
mvn clean dependency:copy-dependencies package
is created a jar with dependencies in lib folder with a thin classloader
在 JIJConstants 中将“Rsrc-Class-Path”编辑为“Class-Path”
mvn clean dependency:copy-dependencies 包
在 lib 文件夹中创建了一个带有依赖项的 jar,并带有一个瘦类加载器
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*</include>
</includes>
<targetPath>META-INF/</targetPath>
</resource>
<resource>
<directory>${project.build.directory}/dependency/</directory>
<includes>
<include>*.jar</include>
</includes>
<targetPath>lib/</targetPath>
</resource>
</resources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${project.mainClass}</mainClass>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Rsrc-Main-Class>${project.realMainClass} </Rsrc-Main-Class>
<Class-Path>./</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
回答by millebi
I am creating an installer that runs as a Java JAR file and it needs to unpack WAR and JAR files into appropriate places in the installation directory. The dependency plugin can be used in the package phase with the copy goal and it will download any file in the Maven repository (including WAR files) and write them where ever you need them. I changed the output directory to ${project.build.directory}/classes and then end result is that the normal JAR task includes my files just fine. I can then extract them and write them into the installation directory.
我正在创建一个作为 Java JAR 文件运行的安装程序,它需要将 WAR 和 JAR 文件解压缩到安装目录中的适当位置。依赖插件可以在具有复制目标的包阶段使用,它将下载 Maven 存储库中的任何文件(包括 WAR 文件)并将它们写入您需要的任何地方。我将输出目录更改为 ${project.build.directory}/classes 然后最终结果是正常的 JAR 任务包含我的文件就好了。然后我可以提取它们并将它们写入安装目录。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>getWar</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>the.group.I.use</groupId>
<artifactId>MyServerServer</artifactId>
<version>${env.JAVA_SERVER_REL_VER}</version>
<type>war</type>
<destFileName>myWar.war</destFileName>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
</configuration>
</execution>
</executions>