我想将我的项目打包在一个可执行的JAR中进行分发。

如何使Maven项目将所有依赖JAR打包到输出JAR中?


当前回答

接受IAdapter的回答并重新格式化,我们可以:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

接下来,我建议将其作为构建的自然部分,而不是显式调用。要使其成为构建的一部分,请将此插件添加到pom.xml中,并将其绑定到包生命周期事件。然而,一个棘手的问题是,如果将其放在pom.xml中,则需要调用assembly:single目标,而如果从命令行手动执行,则会调用“assembly:assembly”。

<project>
  [...]
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <configuration>
                  <archive>
                      <manifest>
                          <addClasspath>true</addClasspath>
                          <mainClass>fully.qualified.MainClass</mainClass>
                      </manifest>
                  </archive>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
              </configuration>
              <executions>
                  <execution>
                      <id>make-my-jar-with-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      [...]
      </plugins>
    [...]
  </build>
</project>

其他回答

如果您真的想重新打包单个结果JAR中的其他JAR内容,另一个选项是Maven Assembly插件。它通过<unpack>true</unpack>解包,然后将所有内容重新打包到一个目录中。然后,您将有第二个过程,将其构建到一个大型JAR中。

另一个选项是OneJar插件。这将在一个步骤中执行上述重新打包操作。

使用maven-assembly-plugin-2.2.1查找共享程序集文件有什么问题?

尝试使用descriptorId配置参数,而不是描述符/描述符或descriptorRefs/descriptorRef参数。

它们都不做您需要的事情:在类路径上查找文件。当然,您需要在maven程序集插件的类路径中添加共享程序集所在的包(见下文)。如果您使用的是Maven 2.x(而不是Maven 3.x),则可能需要在pluginManagement部分的最顶层父pom.xml中添加此依赖项。

有关详细信息,请参见此。

类:org.apache.maven.plugin.assembly.io.DefaultAssemblyReader

例子:

<!-- Use the assembly plugin to create a zip file of all our dependencies. -->
<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.2.1</version>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
            <configuration>
                <descriptorId>assembly-zip-for-wid</descriptorId>
            </configuration>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>cz.ness.ct.ip.assemblies</groupId>
            <artifactId>TEST_SharedAssemblyDescriptor</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</plugin>

我比较了本文中提到的树插件。我生成了两个JAR文件和一个包含所有JAR文件的目录。我比较了结果,肯定maven shade插件是最好的。

我的挑战是我有多个需要合并的Spring资源,以及jax-rs和JDBC服务。与maven汇编插件相比,它们都被shade插件正确合并。在这种情况下,除非您将它们复制到自己的资源文件夹中并手动合并一次,否则Spring将失败。

两个插件都输出正确的依赖树。我有多个作用域,如测试、提供、编译等。两个插件都跳过了测试和提供。他们都生成了相同的清单,但我能够使用他们的转换器使用shade插件合并许可证。使用maven依赖插件当然不会有这些问题,因为JAR文件没有被提取。但正如其他人所指出的,您需要携带一个额外的文件才能正常工作。

以下是pom.xml文件的片段:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <includeScope>compile</includeScope>
                <excludeTransitive>true</excludeTransitive>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <mainClass>com.rbccm.itf.cdd.poller.landingzone.LandingZonePoller</mainClass>
            </manifest>
        </archive>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
    </configuration>
    <executions>
        <execution>
            <id>make-my-jar-with-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.4.3</version>
    <configuration>
        <shadedArtifactAttached>false</shadedArtifactAttached>
        <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
        <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/services/javax.ws.rs.ext.Providers</resource>
            </transformer>
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/spring.factories</resource>
            </transformer>
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/spring.handlers</resource>
            </transformer>
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/spring.schemas</resource>
            </transformer>
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/spring.tooling</resource>
            </transformer>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer">
            </transformer>
        </transformers>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>

你可以结合maven shade插件和maven jar插件。

maven shade插件将您的类和所有依赖项打包在一个JAR文件中。配置maven jar插件以指定可执行jar文件的主类(请参阅“设置类路径”一章“使jar可执行”)。

maven jar插件的POM配置示例:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.example.MyMainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

最后通过调用以下命令创建可执行JAR文件:

mvn clean package shade:shade

接受IAdapter的回答并重新格式化,我们可以:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

接下来,我建议将其作为构建的自然部分,而不是显式调用。要使其成为构建的一部分,请将此插件添加到pom.xml中,并将其绑定到包生命周期事件。然而,一个棘手的问题是,如果将其放在pom.xml中,则需要调用assembly:single目标,而如果从命令行手动执行,则会调用“assembly:assembly”。

<project>
  [...]
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <configuration>
                  <archive>
                      <manifest>
                          <addClasspath>true</addClasspath>
                          <mainClass>fully.qualified.MainClass</mainClass>
                      </manifest>
                  </archive>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
              </configuration>
              <executions>
                  <execution>
                      <id>make-my-jar-with-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      [...]
      </plugins>
    [...]
  </build>
</project>