在Maven的jar中包含依赖项


353

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

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

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




2
如何在Maven的jar文件中包含jar文件?
库什·帕特尔

Answers:


488

您可以使用带有“ 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>

30
attached目标已被弃用。该singledirectory-single目标应改为首选。
Pascal Thivent,2009年

16
directory-single现在也已弃用。
詹姆斯·麦克马洪

14
建议在官方网站上使用单曲
mateuszb 2013年

42
如果有任何新的mvn人员像我一样卡住,请将插件添加到<project>内<build>内的<plugins>中。
DA

10
@ Christian.tucker在目标目录中创建了一个第二个jar,如下所示: ./target / example
技术专家2015年

145

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

如果要在正常构建过程中创建该程序集,则应将单个目录目标(该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元素以适合您的需求(例如,使用清单中的内容)。


我正尝试这样做,但是即使构建顺利执行,插件也不会运行,也不会创建jar文件。我可能会遇到一个常见的陷阱吗?
posdef,2012年

6
它为我工作,但有一个要求。在构建之后,现在创建了两个jar,一个带有项目artifactid-version,另一个带有artifactid-version-“ jar-with-dependencies”。但是我只想制造一个罐子。是否有任何其他的方式
Souvik巴塔查里亚

38

如果您想执行一个可执行的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>

2
为什么jar的名称后面加上“ jar-with-dependencies”?任何解决方法?
蒂娜·J

1
@Tina J您可以<appendAssemblyId>false</appendAssemblyId><configuration>标签内添加,以在最终名称中排除“ -jar-with-dependencies”后缀。
ccu


17

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

14

如果您(像我一样)不特别喜欢上述的jar-with-dependencies方法,那么我更喜欢的Maven解决方案是简单地构建一个WAR项目,即使它只是您正在构建的独立Java应用程序也是如此:

  1. 制作一个普通的maven jar项目,该项目将构建您的jar文件(没有依赖项)。

  2. 另外,设置一个maven war-project(仅包含一个空的src / main / webapp / WEB-INF / web.xml文件,这将避免在maven-build中出现警告/错误),并且仅将jar-project作为一个依赖项,并使jar项目成为<module>war项目下的对象。(此战争项目只是将所有jar文件依赖项包装为zip文件的简单技巧。)

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

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

现在,您的jar和运行应用程序所需的所有依赖项都应该有一个lib目录(您可以将其移动到所需的位置):

java -cp 'path/lib/*' MainClass

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

我认为这既可以在maven中进行设置(无需弄乱装配插件),也可以让您更清楚地了解应用程序结构(可以在纯视图中看到所有相关jar的版本号,避免将所有内容都塞进一个jar文件中)。


是否与Eclipse“导出为可运行的jar”相同?因为这样您可以选择“使用JAR打包所有依赖项”,因此可以将所有依赖项放在jar的project-lib文件夹中。
WesternGun

@FaithReaper-可能是“相同”,我从未尝试过。但是我想如果您使用Eclipse,则不容易编写脚本,如果要实现自动化的 build + deploy-pipeline ,这是必需的。例如,让Jenkins-server从git source-repository或类似的库中进行构建。
罗普

12

http://fiji.sc/Uber-JAR提供了关于替代方案的出色解释:

构造uber-JAR的常见方法有三种:

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

1
关于服务不是很正确,shade插件具有转换器,其中之一是用于连接目录下文件的内容META-INF/services。此处的更多信息:maven.apache.org/plugins/maven-shade-plugin/examples/…–
体外,

7
        <!-- Method 1 -->
        <!-- Copy dependency libraries jar files to a separated LIB folder -->
        <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>


        <!-- Method 2 -->
        <!-- Package all libraries classes into one runnable 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>            

4

我在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.internal.jarinjarloader.JarRsrcLoader</project.mainClass> <project.realMainClass>my.Class</project.realMainClass>

编辑在JIJConstants“RSRC级路径”到“类路径”
MVN清洁依赖性:复制的依赖包
创建与lib文件夹相关性的罐用薄的类加载器

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

maven-dependency-plugin <outputDirectory>不起作用,总是写在“ dependency”文件夹上
Glaucio Southier

创建一个带有内部文件夹“ dependency”的罐子,其中包含项目依赖项,并将其放在MANIFEST.MF
Glaucio Southier,2015年

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

1
基于这个答案,我创建了这个项目。除了pom文件外,您无需更改任何其他内容:github.com/raisercostin/jarinjarloader
–raisercostin


0

这个帖子可能有点老了,但是最近我也遇到了同样的问题。John Stauffer提出的第一个解决方案是一个很好的解决方案,但是今年春季我工作时遇到了一些问题。我使用的spring依赖罐具有一些属性文件和xml-schemas声明,它们共享相同的路径和名称。尽管这些罐子来自相同的版本,但是具有依赖关系罐子 maven-goal用找到的最后一个文件覆盖了这些文件。

最后,由于弹簧罐找不到正确的属性文件,该应用程序无法启动。在这种情况下,由Rop提出的解决方案已经解决了我的问题。

从那时起,spring-boot项目现在就存在了。它通过提供一个Maven目标(使包目标过载)并提供自己的类加载器来解决此问题,这是一种非常酷的方法。参见spring-boots参考指南


0

看看这个答案:

我正在创建一个作为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>


0

谢谢,我在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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.