Maven 可执行 JAR
最后修改于 2025 年 6 月 9 日
在本文中,我们将展示如何使用 Maven Assembly Plugin 创建包含所有依赖项的可执行 JAR 文件。
可执行 JAR(也称为“fat JAR”或“uber JAR”)不仅包含编译后的代码,还包含运行应用程序所需的所有依赖项。这使得分发和部署更加简单,因为用户只需下载一个文件。
基本可执行 JAR 示例
让我们从一个简单的示例开始,该示例演示如何使用 Assembly 插件和内置的 jar-with-dependencies 描述符来创建可执行 JAR。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>executable-jar-example</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.App</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
此 POM 配置创建了一个包含所有依赖项的可执行 JAR。Assembly 插件配置为在 package 阶段运行,并使用内置的 jar-with-dependencies 描述符。
<mainClass>com.example.App</mainClass>
指定包含 main 方法的主类。运行 JAR 时,将使用 java -jar 执行此类。
<descriptorRef>jar-with-dependencies</descriptorRef>
使用内置的 assembly 描述符,该描述符将所有依赖项包含在最终的 JAR 文件中。
<phase>package</phase> <goal>single</goal>
配置插件在 package 阶段运行并执行 single 目标,该目标会创建 assembly。
示例应用程序
让我们创建一个使用 Gson 库的简单应用程序来演示依赖项的包含
package com.example;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.HashMap;
import java.util.Map;
public class App {
public static void main(String[] args) {
System.out.println("Creating executable JAR example");
// Create a sample object to serialize
Map<String, Object> data = new HashMap<>();
data.put("name", "Maven Assembly Example");
data.put("version", "1.0.0");
data.put("executable", true);
// Use Gson to convert to JSON
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(data);
System.out.println("Application data:");
System.out.println(json);
System.out.println("Executable JAR created successfully!");
}
}
构建可执行 JAR
要创建可执行 JAR,请运行以下 Maven 命令
$ mvn clean package
这将在 target 目录中创建两个 JAR 文件
target/ ├── executable-jar-example-1.0.0.jar # Regular JAR └── executable-jar-example-1.0.0-jar-with-dependencies.jar # Executable JAR
运行可执行 JAR
您现在可以直接运行可执行 JAR
$ java -jar target/executable-jar-example-1.0.0-jar-with-dependencies.jar
Creating executable JAR example
Application data:
{
"name": "Maven Assembly Example",
"version": "1.0.0",
"executable": true
}
Executable JAR created successfully!
自定义 Assembly 描述符
为了更精确地控制 assembly 过程,您可以创建自定义的 assembly 描述符。这允许您精确指定包含的内容以及 JAR 的结构。
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.1
http://maven.apache.org/xsd/assembly-2.1.1.xsd">
<id>executable</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>
此自定义描述符指定了以下功能
- 格式:输出格式设置为 JAR。
- 包含基础目录:设置为 false,因此内容直接放置在 JAR 的根目录中。
- 依赖项集:包含所有运行时依赖项,并解压到 JAR 的根目录。
- 文件集:包含项目输出目录中的所有编译类和资源。
- 输出目录:指定包含文件的根目录。
- 包含:包含输出目录中的所有文件。
- 解压:将所有运行时依赖项解压到 JAR 的根目录。
- 使用项目工件:设置为 false,因此项目的主工件不包含在依赖项中。
- 范围:设置为 runtime,因此仅包含运行时依赖项。
- 输出目录:指定依赖项在 JAR 中的放置位置。
现在更新 POM 以使用自定义描述符
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.App</mainClass>
</manifest>
</archive>
<descriptors>
<descriptor>src/main/assembly/jar-with-dependencies.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
此配置指定了要使用的自定义 assembly 描述符文件,而不是内置的 jar-with-dependencies 描述符。
<descriptors>
<descriptor>src/main/assembly/jar-with-dependencies.xml</descriptor>
</descriptors>
指向自定义 assembly 描述符文件,而不是使用内置的 jar-with-dependencies 描述符。
<dependencySet>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
将所有运行时依赖项解压到 JAR 的根目录,使其可供应用程序使用。
多个主类示例
有时您需要从同一个项目创建多个可执行 JAR,每个 JAR 都有不同的主类。方法如下
package com.example;
public class ServerApp {
public static void main(String[] args) {
System.out.println("Starting server application...");
System.out.println("Server is running on port 8080");
// Simulate server running
try {
Thread.sleep(2000);
System.out.println("Server stopped gracefully");
} catch (InterruptedException e) {
System.err.println("Server interrupted: " + e.getMessage());
}
}
}
这是一个简单的服务器应用程序,模拟启动服务器并在短暂延迟后停止。它向控制台打印消息以指示服务器的状态。您可以运行此应用程序以查看其作为独立服务器应用程序的行为。
package com.example;
public class ClientApp {
public static void main(String[] args) {
System.out.println("Starting client application...");
System.out.println("Connecting to server at localhost:8080");
System.out.println("Client operation completed");
}
}
这是一个简单的客户端应用程序,模拟连接到服务器并执行客户端操作。它向控制台打印消息以指示客户端的操作。您可以运行此应用程序以查看其作为独立客户端应用程序的行为。
为每个应用程序创建单独的 Assembly 描述符
<assembly>
<id>server</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
<assembly>
<id>client</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
在 POM 中配置多个插件执行
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>server-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>com.example.ServerApp</mainClass>
</manifest>
</archive>
<descriptors>
<descriptor>src/main/assembly/server.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution>
<id>client-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>com.example.ClientApp</mainClass>
</manifest>
</archive>
<descriptors>
<descriptor>src/main/assembly/client.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
构建后,您将拥有多个可执行 JAR
$ mvn clean package $ ls target/*.jar executable-jar-example-1.0.0.jar executable-jar-example-1.0.0-client.jar executable-jar-example-1.0.0-server.jar
单独运行每个应用程序
$ java -jar target/executable-jar-example-1.0.0-server.jar Starting server application... Server is running on port 8080 Server stopped gracefully $ java -jar target/executable-jar-example-1.0.0-client.jar Starting client application... Connecting to server at localhost:8080 Client operation completed
Assembly 插件配置选项
Assembly 插件提供了许多配置选项来定制最终的 JAR
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<!-- Append assembly id to final name -->
<appendAssemblyId>true</appendAssemblyId>
<!-- Custom final name -->
<finalName>my-app</finalName>
<!-- Archive configuration -->
<archive>
<manifest>
<mainClass>com.example.App</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Built-By>Maven Assembly Plugin</Built-By>
<Implementation-Version>${project.version}</Implementation-Version>
</manifestEntries>
</archive>
<!-- Attach assembled artifacts to project -->
<attach>true</attach>
<!-- Skip assembly if no descriptor found -->
<skipAssembly>false</skipAssembly>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<appendAssemblyId>true</appendAssemblyId>
控制是否将 assembly ID 追加到最终的 JAR 名称。如果为 true,则创建如 myapp-1.0-jar-with-dependencies.jar 这样的文件。
<addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix>
向清单添加类路径条目,并为依赖项 JAR 指定前缀。在创建基于目录的分发时很有用。
来源
在本文中,我们展示了如何使用 Maven Assembly Plugin 创建包含所有依赖项的可执行 JAR 文件。
作者
列出所有Java教程。