【问题标题】:Including dependencies in a jar with Maven使用 Maven 在 jar 中包含依赖项
【发布时间】:2010-12-16 06:56:23
【问题描述】:

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

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

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

【问题讨论】:

标签: java maven-2 jar packaging


【解决方案1】:

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

【讨论】:

  • 如果任何新的 mvn 人像我一样被卡住,请将插件添加到 内的 内的 中。
  • 如何避免在我的代码中包含我不使用的库?我只使用 SSJ 的 jar 总计 10 MB :(
  • @D.A.为什么人们会遗漏这样的相关(阅读:相关)细节,这超出了我的理解。
  • @Christian.tucker 在目标目录中有一个像这样创建的第二个 jar:./target/example-0.0.1-SNAPSHOT.jar./目标/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
  • 只需在配置中添加一件事。您的主要课程信息。 完全限定名
【解决方案2】:

对于 Maven 2,正确的做法是使用 Maven2 Assembly Plugin,它有一个 pre-defined descriptor file 用于此目的,您可以在命令行上使用它:

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>

如果您想创建该程序集作为正常构建过程的一部分,您应该将singledirectory-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 元素以满足您的需求(例如,使用清单内容作为语音)。

【讨论】:

  • 我正在尝试这个,但是插件没有运行,并且即使构建执行顺利,也没有创建 jar 文件。有没有我可能会遇到的常见陷阱?
  • 它对我有用,但有一个任务。在构建之后,现在创建了两个 jar,一个使用项目 artifactid-version,另一个使用 artifactid-version-“jar-with-dependencies”。但我只想建造一个罐子。有没有其他办法
  • @SouvikBhattacharya 将&lt;appendAssemblyId&gt;false&lt;/appendAssemblyId&gt; 添加到maven-assembly-plugin 配置。
【解决方案3】:

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

【讨论】:

  • 为什么jar的名字后面要加上“jar-with-dependencies”?!有什么解决方法吗?
  • @Tina J 您可以在&lt;configuration&gt; 标签内添加&lt;appendAssemblyId&gt;false&lt;/appendAssemblyId&gt; 以排除最终名称中的“-jar-with-dependencies”后缀。
【解决方案4】:

这是shade maven plugin。它可用于打包和重命名依赖项(以省略类路径上的依赖问题)。

【讨论】:

【解决方案5】:

您可以使用 &lt;classifier&gt; 标签来使用新创建的 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>

【讨论】:

    【解决方案6】:
            <!-- 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>            
    

    【讨论】:

    • 第一个选项是更快重建的最佳选择。 assembly-plugin 只是在打包依赖时花费了太多时间,这是意料之中的。
    • 我在这里尝试了第一种方法。在文档中,它声明“”注意:Class-Path 标头指向本地网络上的类或 JAR 文件,而不是 JAR 文件中的 JAR 文件或可通过 Internet 协议访问的类。要将 JAR 文件中的 JAR 文件中的类加载到类路径中,您必须编写自定义代码来加载这些类。”在您的方法 1 中,您是指人们编写自定义 jar 加载器吗?
    • 我注意到与程序集相比,复制和解包存在差异。尝试为我的服务器运行我的 jar 文件时,我不断收到“ClassNotFoundException”。如果使用您的方法 1,您建议如何进行?我无法让我的工作。
    【解决方案7】:

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

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

    2. 另外,设置一个 Maven 战争项目(只有一个空的 src/main/webapp/WEB-INF/web.xml 文件,这将避免在maven-build),它只有你的 jar-project 作为依赖项,并让你的 jar-project 在你的 war-project 下成为 &lt;module&gt;。 (这个战争项目只是将所有 jar 文件依赖项打包到一个 zip 文件中的一个简单技巧。)

    3. 构建战争项目以生成战争文件。

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

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

    java -cp 'path/lib/*' MainClass
    

    (类路径中的通配符适用于 Java-6 或更高版本)

    我认为这在 maven 中设置起来更简单(无需乱用程序集插件),还可以让您更清晰地查看应用程序结构(您将清楚地看到所有依赖 jar 的版本号查看,并避免将所有内容都塞进一个 jar 文件中)。

    【讨论】:

    • 和Eclipse“导出为可运行jar”一样吗?因为有了这个,您可以选择“使用 JAR 打包所有依赖项”,然后您可以在 project-lib 文件夹中获取所有依赖项,以及您的 jar。
    • @FaithReaper -- 可能是“相同的”,我从未尝试过。但我想如果你使用 Eclipse,它不容易编写脚本,这是一个要求,如果你想实现 automated build+deploy-pipeline。例如,让 Jenkins-server 从您的 git source-repository 或类似的地方进行构建。
    【解决方案8】:

    http://fiji.sc/Uber-JAR 很好地解释了替代方案:

    构建 uber-JAR 的常用方法有以下三种:

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

    【讨论】:

    • 关于服务不太正确,shade 插件有转换器,其中之一是用于连接META-INF/services 目录下的文件内容。更多信息在这里:maven.apache.org/plugins/maven-shade-plugin/examples/…
    • 它基本上将工件封装在自己的命名空间中。我想不出任何仍然允许发生冲突的情况。
    【解决方案9】:

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

    【讨论】:

    • maven-dependency-plugin 不起作用,总是写在“dependency”文件夹中
    • 创建一个包含项目依赖项的内部文件夹“dependency”的jar并将其放在MANIFEST.MF上
    • src/main/java**/*.java**/*.属性src/main/resourcestrue**/*META-INF/${project.build.directory}/dependency/*.jar lib/
    • 基于这个答案,我创建了这个项目。除了 pom 文件,您不需要更改任何内容:github.com/raisercostin/jarinjarloader
    【解决方案10】:

    抛开 Maven,您可以将 JAR 库放在 Main Jar 中,但您需要使用自己的类加载器。

    查看这个项目:One-JAR link text

    【讨论】:

    【解决方案11】:

    谢谢 我在 POM.xml 文件中的 sn-p 下面添加了 Mp 问题并解决了 创建包含所有依赖 jar 的 fat 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>
    

    【讨论】:

      【解决方案12】:

      我试图做类似的事情,但我不希望所有的罐子都包括在内。我想从给定的依赖项中包含一些特定的目录。另外分类器标签已经被占用,所以我不能这样做:

      <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-dependency-plugin 和 unpack 目标
      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>
      

      【讨论】:

        【解决方案13】:

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

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

        同样,从那时起,spring-boot 项目就存在了。它有一种非常酷的方法来管理这个问题,它提供了一个 maven 目标,它重载了包目标并提供了自己的类加载器。见spring-boots Reference Guide

        【讨论】:

          【解决方案14】:

          Have a look at this answer:

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

          【讨论】:

            【解决方案15】:

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

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

            【讨论】:

            • 请描述一下,它究竟是如何解决问题的
            • 我只添加了这个插件
            猜你喜欢
            • 2016-06-04
            • 2023-03-30
            • 1970-01-01
            • 2017-02-01
            • 1970-01-01
            • 2017-02-22
            • 2015-06-27
            • 1970-01-01
            相关资源
            最近更新 更多