如何使用maven创建具有依赖关系的可执行jar?

jogvjijk  于 2021-06-30  发布在  Java
关注(0)|答案(21)|浏览(484)

我想将我的项目打包在一个可执行jar中进行分发。
如何让maven项目将所有依赖jar打包到输出jar中?

sbtkgmzw

sbtkgmzw16#

您可以使用maven依赖插件,但问题是如何创建可执行jar。要做到这一点,需要对matthew franglen的响应进行以下修改(顺便说一句,从一个干净的目标开始使用依赖插件需要更长的时间来构建):

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${basedir}/target/dependency</directory>
        </resource>
    </resources>
</build>
iyfamqjs

iyfamqjs17#

接受未回答者的答案并重新格式化,我们有:

<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 把它绑在 package 生命周期事件。然而,一个问题是你需要打电话给 assembly:single 如果将这个放在pom.xml中,同时调用'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>
yrwegjxp

yrwegjxp18#

使用maven shade插件将所有依赖项打包到一个uberjar中。它还可以通过指定主类来构建可执行jar。在尝试使用maven assembly和maven jar之后,我发现这个插件最适合我的需要。
我发现这个插件特别有用,因为它合并了特定文件的内容,而不是覆盖它们。当jar中有同名的资源文件,并且插件试图打包所有资源文件时,就需要这样做
参见下面的示例

<plugins>
    <!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <artifactSet>
                        <!-- signed jars-->
                            <excludes>
                                <exclude>bouncycastle:bcprov-jdk15</exclude>
                            </excludes>
                        </artifactSet>

                         <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- Main class -->
                                <mainClass>com.main.MyMainClass</mainClass>
                            </transformer>
                            <!-- Use resource transformers to prevent file overwrites -->
                            <transformer 
                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>properties.properties</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>applicationContext.xml</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/cxf/cxf.extension</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>META-INF/cxf/bus-extensions.xml</resource>
                            </transformer>
                     </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>
d8tt03nd

d8tt03nd19#

在包阶段之前,可以使用依赖插件在单独的目录中生成所有依赖项,然后将其包含在清单的类路径中:

<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>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>theMainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

交替使用 ${project.build.directory}/classes/lib 作为outputdirectory将所有jar文件集成到主jar中,但是您需要添加自定义类加载代码来加载jar。

nr7wwzry

nr7wwzry20#

我不会像其他人以前那样直接回答这个问题,但我真的很想知道将所有依赖项嵌入项目的jar本身是否是个好主意。
我明白这一点(易于部署/使用),但这取决于您的项目的用例(可能有替代方案(见下文))。
如果完全独立使用,为什么不呢。
但是,如果您在其他上下文中使用您的项目(比如在webapp中,或者放在其他jar所在的文件夹中),您的类路径中可能有jar副本(文件夹中的那些,jar中的那个)。也许不是出价交易,但我通常避免这样做。
一个好的选择:
将应用程序部署为.zip/.war:归档文件包含项目的jar和所有依赖的jar;
使用动态类加载器机制(请参阅spring,或者您自己也可以轻松地做到这一点)来拥有项目的单个入口点(要启动的单个类-请参阅另一个答案上的清单机制),它将(动态地)向当前类路径添加所有其他需要的jar。
像这样,最后只有一个清单和一个“特殊的动态类加载器主”,您可以从以下内容开始您的项目:

java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass
anhgbhbe

anhgbhbe21#

要从命令行本身创建可执行jar,只需从项目路径运行以下命令:

mvn assembly:assembly

相关问题