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教程。