在Maven的jar中包含依赖项

有没有办法强制maven(2.0.9)将所有依赖项包含在一个jar文件中?

我有一个项目的构建到一个单一的jar文件。我希望依赖的类也能复制到jar中。

我知道我不能在一个jar文件中包含一个jar文件。我正在寻找一种方法来解包指定为依赖项的jar,并将类文件打包到我的jar中。

574649 次浏览

你可以使用带有"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>

这是Shade maven插件。它可以用于打包和重命名依赖关系(以忽略类路径上的依赖关系问题)。

在Maven 2中,正确的方法是使用Maven2汇编插件,它有一个预定义描述符文件,你可以在命令行中使用:

mvn assembly:assembly -DdescriptorId=jar-with-dependencies

如果你想让这个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>

如果你想创建这个程序集作为正常构建过程的一部分,你应该将directory-single目标(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>

调整configuration元素以适应您的需要(例如使用所述的清单内容)。

把Maven放在一边,您可以把JAR库放在Main JAR中,但是您需要使用自己的类加载器。

检查这个项目:One-JAR 链接文本

您可以使用<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>
如果你(像我一样)不是特别喜欢上面描述的jar-with-dependencies方法, 我更喜欢的maven解决方案是简单地建立一个war项目, 即使您正在构建的只是一个独立的Java应用程序:

  1. 创建一个普通的maven jar-project,它将构建您的jar文件(没有依赖项)。

  2. 同时,设置一个maven war-project(只有一个空的src/main/webapp/WEB-INF/web.xml文件,这将避免在maven-build中出现警告/错误),它只将你的jar-project作为依赖项,并使你的jar-project在你的war-project下成为<module>。(这个war-project只是一个简单的技巧,可以将所有jar文件依赖项打包到zip文件中。)

  3. 建立战争项目,生产战争档案。

  4. 在部署步骤中,只需将.war文件重命名为*.zip并解压缩。

你现在应该有一个lib目录(你可以移动到你想要的地方),里面有你的jar和运行应用程序所需的所有依赖项:

java -cp 'path/lib/*' MainClass

(类路径中的通配符在Java-6或更高版本中有效)

我认为这样在maven中设置起来更简单(不需要使用汇编插件),而且可以更清楚地看到应用程序结构(您将在普通视图中看到所有依赖jar的版本号,并避免将所有内容都塞进一个jar文件中)。

这篇文章可能有点老,但我最近也遇到了同样的问题。John Stauffer 提出的第一个解决方案很好,但是我在今年春天工作的时候遇到了一些问题。我使用的 Spring 依赖项 jar 有一些属性文件和 xml-schema 声明,它们共享相同的路径和名称。虽然这些 jar 来自相同的版本,但是 带依赖项的 jar的目标是用最后找到的文件覆盖这些文件。

最后,应用程序无法启动,因为 Spring jar 无法找到正确的属性文件。在这种情况下,罗普提出的解决方案解决了我的问题。

此外,从那时起,春季启动项目现在已经存在。它有一个非常酷的方法来管理这个问题,它提供了一个 maven 目标,超载了包目标,并提供了自己的类装入器。参见 弹簧靴参考指南

Http://fiji.sc/uber-jar 对替代方案提供了极好的解释:

构建一个 uber-JAR 有三种常用的方法:

  1. 解压所有 JAR 文件,然后将它们重新打包到一个 JAR 中。
    • 优点: 可以使用 Java 的默认类装入器。
    • 缺点: 存在于具有相同路径的多个 JAR 文件中的文件(例如, META-INF/services/javax.script. ScriptEngineFactory)将覆盖一个 另一个,导致错误的行为。
    • 工具: Maven Assembly 插件,Classworld Uberjar
  2. 与无阴影相同,但是重命名(例如,“阴影”)所有依赖项的所有包。
    • 优点: 可以使用 Java 的默认类装入器。 避免一些(并非全部)依赖项版本冲突。
    • 反对: 文件 存在于具有相同路径的多个 JAR 文件中(例如, META-INF/services/javax.script. ScriptEngineFactory)将覆盖一个 另一个,导致错误的行为。
    • 工具: Maven Shade 插件
  3. 最终的 JAR 文件包含嵌入其中的其他 JAR 文件。
    • 优点: 避免依赖版本冲突 保存资源文件。
    • 缺点: 需要捆绑一个特殊的 “ bootstrap”类加载器,使 Java 能够从 调试类装入器问题变得更加复杂。
    • 工具: Eclipse JAR 文件导出程序,One-JAR。

我对 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/; 这个类加载器是最好的一个类加载器和非常快;

< project.mainClass > org.eclipse.jdt.interal.jarinjarloader. JarRsrcLoader < project.realMainClass > my. Class

在 JIJConstants 中编辑“ Rsrc-Class-Path”到“ Class-Path”
Mvn clean 依赖项: 复制依赖项包
使用瘦类加载器在 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>

看看这个答案:

我正在创建一个作为 JavaJAR 文件运行的安装程序,它需要将 WAR 和 JAR 文件解压缩到安装目录中的适当位置。这个依赖项插件可以在包阶段使用,它可以下载 Maven 存储库中的任何文件(包括 WAR 文件) ,并在需要的任何地方编写它们。我将输出目录更改为 ${ project.build.direct}/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>

谢谢 我已经在 POM.xml 文件中添加了以下代码片段,解决了 Mp 问题 创建包含所有依赖 jar 的胖 jar 文件。

<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>

如果你想做一个可执行的 jar 文件,他们也需要设置主类。所以完整的配置应该是。

    <plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- ... -->
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>

方法1: 将依赖项的 JAR 文件复制到 target/lib中,然后在 MANIFEST 中将它们添加到 JAR 的类路径中:

        <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<excludeTransitive>false</excludeTransitive>
<stripVersion>false</stripVersion>
</configuration>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Add LIB folder to classPath -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>

方法2: 将所有依赖项解包,并将它们的类和资源重新打包到一个平面 JAR 中。注意: 重叠的资源将随机丢失!

<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>

为了使它更简单,您可以使用下面的插件。

             <plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>spring-boot</classifier>
<mainClass>
com.nirav.certificate.CertificateUtility
</mainClass>
</configuration>
</execution>
</executions>
</plugin>

我也想做类似的事情,但是我不想把所有的罐子都包括在内。我希望包含来自给定依赖项的一些特定目录。此外,分类器标签已经被占用,所以我不能做:

<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>
  1. 我使用了 maven 依赖性插件和解压缩目标
  2. 并将我想要的东西解包到 ${project.build.directory}/classes,否则将被省略
  3. 因为它在 classes 目录中,所以 maven 最终将它放在 jar 中
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>my.group</groupId>
<artifactId>my.artifact</artifactId>
<classifier>occupied</classifier>
<version>1.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<includes>aaa/**, bbb/**, ccc/**</includes>
</configuration>
</execution>
</executions>
</plugin>