使用Maven在jar中包含依赖项

时间:2009-11-13 12:51:24

标签: java maven-2 jar packaging

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

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

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

14 个答案:

答案 0 :(得分:431)

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

答案 1 :(得分:125)

使用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元素以满足您的需求(例如,使用所显示的清单内容)。

答案 2 :(得分:28)

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

答案 3 :(得分:17)

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

答案 4 :(得分:13)

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

答案 5 :(得分:12)

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

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

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

  3. 构建war-project以生成war文件。

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

  5. 你现在应该有一个lib目录(可以移动到你想要的位置)和你的jar以及运行你的应用程序所需的所有依赖项:

    java -cp 'path/lib/*' MainClass
    

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

    我认为这在maven中设置起来更简单(不需要使用程序集插件)并且还可以让您更清楚地了解应用程序结构(您将看到所有相关jar的版本号在普通查看,并避免将所有内容堵塞到一个jar文件中。)

答案 6 :(得分:10)

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

  

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

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

答案 7 :(得分:3)

    $data = array(
      "title" => "hello",
      "description" => "test test test"
    );

    echo $data;

答案 8 :(得分:1)

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

检查此项目:One-JAR link text

答案 9 :(得分:0)

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

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

此后,Spring-boot项目现在也存在。通过提供一个重载包目标并提供自己的类加载器的maven目标,它有一种非常酷的方式来管理这个问题。见spring-boots Reference Guide

答案 10 :(得分:0)

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>

答案 11 :(得分: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>

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

我试图做类似的事情,但我不想包含所有的罐子。我想从给定的依赖项中包含一些特定的目录。另外classifier标签已经被占用了,所以我做不到:

<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 并解压了目标
  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>