1. 概述

本教程将聚焦于如何将 Maven 项目打包成可执行 JAR 文件。当创建 JAR 文件时,我们通常希望无需 IDE 即可直接运行。为此,我们将探讨每种实现方式的配置、优缺点及适用场景。

2. 基础配置

创建可执行 JAR 不需要额外依赖,只需一个标准的 Maven Java 项目,并至少包含一个带有 main(...) 方法的类。示例中我们创建了名为 ExecutableMavenJar 的类。

确保 pom.xml 包含以下核心配置:

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

⚠️ 关键点: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>

核心要点:

  1. copy-dependencies 目标将依赖复制到 outputDirectory(本例为 target/libs
  2. 创建可执行 JAR 时需在 MANIFEST 中声明类路径和主类:
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>libs/</classpathPrefix>
                <mainClass>
                    com.baeldung.executable.ExecutableMavenJar
                </mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

✅ 优点:流程透明可控
❌ 缺点:依赖需外部存放(libs 目录),JAR 文件需与该目录共存才能运行

2.2 Apache Maven Assembly Plugin

Assembly Plugin 可将项目输出、依赖、文档等聚合为单个可运行包。核心目标是 single(其他目标已废弃):

<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.baeldung.executable.ExecutableMavenJar
                    </mainClass>
                </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </execution>
    </executions>
</plugin>

输出文件名示例:core-java-jar-with-dependencies.jar

✅ 优点:依赖全打包进 JAR,单文件部署
❌ 缺点:打包控制能力有限(如不支持类重定位)

2.3 Apache Maven Shade Plugin

Shade Plugin 可创建包含所有依赖的 "uber-jar",并支持依赖包重命名(shading):

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

输出文件名示例:core-java-0.1.0-SNAPSHOT-shaded.jar

✅ 优点:依赖全打包,支持高级功能(shading/类重定位)
❌ 缺点:配置较复杂(尤其使用高级特性时)

2.4 One Jar Maven Plugin

One Jar 提供自定义类加载器,可直接从 JAR 内部加载依赖(而非文件系统):

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

✅ 优点:清晰的类加载模型,支持外部 JAR 和原生库
❌ 缺点:自 2012 年后停止维护

2.5 Spring Boot Maven Plugin

即使非 Spring Boot 项目,也可用此插件打包可执行 JAR/WAR:

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

✅ 优点:依赖全打包,支持 WAR 打包、依赖排除等高级功能
❌ 缺点:会引入不必要的 Spring Boot 相关类

2.6 嵌入式 Tomcat 的 Web 应用

使用 tomcat7-maven-plugin 打包独立 Web 应用:

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

执行 mvn package 后生成 webapp.jar,通过 java -jar target/webapp.jar 启动,访问 localhost:8080 测试。

⚠️ 注意:Servlet 依赖需设为 provided scope 以免冲突:

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

✅ 优点:单文件部署简单
❌ 缺点:因嵌入 Tomcat 导致文件体积较大

2.7 使用 Launch4j 生成 Windows 可执行文件

通过 launch4j-maven-plugin 将 JAR 转为 .exe

<plugin>
    <groupId>com.akathist.maven.plugins.launch4j</groupId>
    <artifactId>launch4j-maven-plugin</artifactId>
    <version>2.5.3</version>
    <executions>
        <execution>
            <id>l4j-clui</id>
            <phase>package</phase>
            <goals>
                <goal>launch4j</goal>
            </goals>
            <configuration>
                <headerType>gui</headerType>
                <outfile>${project.build.directory}/${project.build.finalName}.exe</outfile>
                <jar>${project.build.directory}/${project.build.finalName}.jar</jar>
                <errTitle>App Error</errTitle>
                <classPath>
                    <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass>
                </classPath>
            </configuration>
        </execution>
    </executions>
</plugin>

执行 mvn clean package 后在 target 目录生成 .exe 文件。

✅ 优点:简化 Windows 用户分发流程
❌ 缺点:仅限 Windows 平台

3. 创建多个可运行 JAR

当项目需包含多个主类时,可通过以下方式生成独立 JAR:

3.1 使用 maven-assembly-plugin

配置多执行方案:

<profile>
    <id>multiple-jar-profile</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <id>create-jar-for-main1</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>com.baeldung.multiplejar.Main1</mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                            <finalName>main1-runnable</finalName>
                            <appendAssemblyId>false</appendAssemblyId>
                        </configuration>
                    </execution>
                    <execution>
                        <id>create-jar-for-main2</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>com.baeldung.multiplejar.Main2</mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                            <finalName>main2-runnable</finalName>
                            <appendAssemblyId>false</appendAssemblyId>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

执行命令:

mvn clean package -Pmultiple-jar-profile

生成文件:

main1-runnable.jar
main2-runnable.jar

测试命令:

java -jar target/main1-runnable.jar  # 输出: Hello from Main1!
java -jar target/main2-runnable.jar  # 输出: Hello from Main2!

3.2 使用 maven-shade-plugin

替代方案配置:

<profile>
    <id>multiple-jar-profile2</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>${maven-shade-plugin.version}</version>
                <executions>
                    <execution>
                        <id>shade-main1</id>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <shadedArtifactAttached>true</shadedArtifactAttached>
                            <shadedClassifierName>main1</shadedClassifierName>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.baeldung.multiplejar.Main1</mainClass>
                                </transformer>
                            </transformers>
                            <finalName>main1-runnable</finalName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>shade-main2</id>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <shadedArtifactAttached>true</shadedArtifactAttached>
                            <shadedClassifierName>main2</shadedClassifierName>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.baeldung.multiplejar.Main2</mainClass>
                                </transformer>
                            </transformers>
                            <finalName>main2-runnable</finalName>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

4. 总结

本文系统介绍了多种 Maven 创建可执行 JAR 的方案:

方案 适用场景 核心优势 主要限制
手动配置 需精细控制依赖 流程透明 依赖需外部存放
Assembly Plugin 简单单文件部署 开箱即用 打包控制弱
Shade Plugin 需依赖隔离/重命名 支持 shading 配置复杂
One Jar 特殊类加载需求 支持外部 JAR 已停止维护
Spring Boot Plugin 复杂项目打包 功能全面 引入冗余类
Tomcat Plugin Web 应用独立部署 内嵌容器 文件体积大
Launch4j Windows 分发 生成 .exe 跨平台限制

测试建议:执行 mvn clean package 构建 JAR 后,通过 java -jar <文件名> 验证。

⚠️ 最后提醒:确保所打包依赖的许可证允许此类操作,虽然多数场景无此限制,但仍需注意合规性。


原始标题:How to Create an Executable JAR with Maven | Baeldung

» 下一篇: Ehcache 介绍