Contents

Maven创建可执行Jar文件

1. 概述

在这个快速教程中,我们将专注于将 Maven 项目打包成可执行的 Jar 文件。

创建jar文件时,我们通常希望轻松运行它,而不使用 IDE。为此,我们将讨论使用这些方法创建可执行文件的配置和优缺点。

2. 配置

我们不需要任何额外的依赖来创建一个可执行的jar。我们只需要创建一个 Maven Java 项目并至少有一个带有*main(…)*方法的类。

在我们的示例中,我们创建了名为ExecutableMavenJar的 Java 类。

我们还需要确保我们的pom.xml包含这些元素:

<modelVersion>4.0.0</modelVersion>
<groupId>com.blogdemo</groupId>
<artifactId>core-java</artifactId>
<version>0.1.0-SNAPSHOT</version>
<packaging>jar</packaging>

这里最重要的方面是类型——要创建一个可执行的jar,请仔细检查配置是否使用了jar类型。

现在我们可以开始使用各种解决方案了。

2.1. 手动配置

让我们在maven-dependency-plugin的帮助下从手动方法开始。

我们首先将所有必需的依赖项复制到我们指定的文件夹中:

<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}/libs
                </outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

有两个重要方面需要注意。

首先,我们指定目标copy-dependencies,它告诉 Maven 将这些依赖项复制到指定的outputDirectory中。在我们的例子中,我们将 在项目构建目录(通常是目标文件夹)中创建一个名为libs的文件夹。

其次,我们将创建可执行和可识别类路径的jar,并在第一步中复制到依赖项的链接:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>libs/</classpathPrefix>
                <mainClass>
                    com.blogdemo.executable.ExecutableMavenJar
                </mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

其中最重要的部分是manifest配置。我们添加一个包含所有依赖项(文件夹libs/)的类路径,并提供有关主类的信息。

请注意,我们需要提供类的完全限定名称,这意味着它将包含包名称。

这种方法的优点和缺点是:

  • 优点- 透明的过程,我们可以指定每个步骤
  • 缺点——手动;依赖项不在最终的jar中,这意味着我们的可执行jar仅在libs文件夹可访问且对jar可见的情况下才会运行

2.2. Apache Maven Assembly 插件

Apache Maven Assembly Plugin 允许用户将项目输出及其依赖项、模块、站点文档和其他文件聚合到一个可运行的包中。

程序集插件中的主要目标是*single-mojo *目标,用于创建所有程序集(所有其他目标均已弃用,并将在未来的版本中删除)。

我们看一下pom.xml中的配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
            <configuration>
                <archive>
                <manifest>
                    <mainClass>
                        com.blogdemo.executable.ExecutableMavenJar
                    </mainClass>
                </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </execution>
    </executions>
</plugin>

与手动方法类似,我们需要提供有关主类的信息。不同之处在于 Maven Assembly Plugin 会自动将所有需要的依赖项复制到一个jar文件中。

在配置代码的descriptorRefs部分,我们提供了将添加到项目名称中的名称。

我们示例中的输出将命名为core-java-jar-with-dependencies.jar

  • 优点– jar文件中的依赖项,只有一个文件
  • cons - 打包我们的工件的基本控制,例如,没有类重定位支持

2.3. Apache Maven Shade 插件

Apache Maven Shade Plugin 提供了将工件打包到uber-jar中的功能,其中包含运行项目所需的所有依赖项。此外,它还支持对某些依赖项的包进行着色(即重命名)。

我们来看看配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <shadedArtifactAttached>true</shadedArtifactAttached>
                <transformers>
                    <transformer implementation=
                      "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.blogdemo.executable.ExecutableMavenJar</mainClass>
                </transformer>
            </transformers>
        </configuration>
        </execution>
    </executions>
</plugin>

此配置包含三个主要部分。

首先,<shadedArtifactAttached>标记所有要打包到jar中的依赖项。

其次,我们需要指定转换器的实现 ;我们在示例中使用了标准的。

最后,我们需要指定应用程序的主类。

输出文件将命名为core-java-0.1.0-SNAPSHOT-shaded.jar,其中core-java是我们的项目名称,后跟快照版本和插件名称。

  • 优点jar文件中的依赖项,打包我们的工件的高级控制,带有阴影和类重定位
  • 缺点 - 复杂的配置(特别是如果我们想使用高级功能)

2.4. 一个 Jar Maven 插件

创建可执行jar的另一种选择是 One Jar 项目。

这提供了一个自定义类加载器,它知道如何从存档中的 jars 加载类和资源,而不是从文件系统中的jars加载。 我们来看看配置:

<plugin>
    <groupId>com.jolira</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.blogdemo.executable.
                  ExecutableMavenJar</mainClass>
                <attachToBuild>true</attachToBuild>
                <filename>
                  ${project.build.finalName}.${project.packaging}
                </filename>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

如配置所示,我们需要指定主类并附加所有依赖项来构建,使用attachToBuild= true

此外,我们应该提供输出文件名。此外,Maven 的目标是one-jar。请注意,One Jar 是一种商业解决方案,它会使依赖项 jar在运行时不会扩展到文件系统中。

  • 优点- 干净的委托模型,允许类位于 One Jar 的顶层,支持外部jar并且可以支持 Native 库
  • 缺点- 自 2012 年以来未得到积极支持

2.5. Spring Boot Maven 插件

最后,我们要看的最后一个解决方案是 Spring Boot Maven 插件。

这允许打包可执行的jarwar档案并“就地”运行应用程序。

要使用它,我们至少需要使用 Maven 3.2 版本。详细说明可在此处 获得。

让我们看一下配置:

<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.blogdemo.executable.ExecutableMavenJar
                </mainClass>
            </configuration>
        </execution>
    </executions>
</plugin>

Spring 插件与其他插件有两个区别:执行的目标称为repackage,分类器称为spring-boot

请注意,我们不需要 Spring Boot 应用程序即可使用此插件。

  • 优点– jar文件中的依赖项,我们可以在每个可访问的位置运行它,对打包我们的工件进行高级控制,从jar文件中排除依赖项等,还可以打包war文件
  • 缺点- 添加可能不必要的 Spring 和 Spring Boot 相关类

2.6. 带有可执行 Tomcat 的 Web 应用程序

在最后一部分,我们要介绍一个打包在一个jar文件中的独立 Web 应用程序。

为此,我们需要使用不同的插件,专为创建可执行 jar 文件而设计:

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.0</version>
    <executions>
        <execution>
            <id>tomcat-run</id>
            <goals>
                <goal>exec-war-only</goal>
            </goals>
            <phase>package</phase>
            <configuration>
                <path>/</path>
                <enableNaming>false</enableNaming>
                <finalName>webapp.jar</finalName>
                <charset>utf-8</charset>
            </configuration>
        </execution>
    </executions>
</plugin>

goal设置为exec-war-only,我们服务器的路径在配置标签内指定,并带有其他属性,如finalNamecharset等。

要构建一个jar,我们运行man package,这将导致在我们的target目录中创建webapp.jar

要运行应用程序,我们只需在控制台中编写java -jar target/webapp.jar并尝试通过在浏览器中指定localhost:8080 来测试它。

  • 优点– 拥有一个文件,易于部署和运行
  • 缺点- 文件的大小要大得多,因为将 Tomcat 嵌入分布打包在一个war文件中

请注意,这是该插件的最新版本,支持 Tomcat7 服务器。为避免错误,我们可以检查我们对 Servlets 的依赖是否已设置为provided范围,否则,在可执行jar的运行时会发生冲突:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <scope>provided</scope>
</dependency>