Maven 的内部
Source: Dev.to
介绍
今天我浪费了两小时宝贵的时间。就是这样。全部都是因为我认为有点怪异的 Maven。
这件事和我的一个副项目 frover(GitHub)有关,它是一个用 Java 编写的文件浏览器。我喜欢 Java 的一点是它非常、非常容易分发:只需要把它打成 JAR(更多信息)即可。
为什么要用 Maven 作为应用的构建系统?好吧,这是一种选择。根据我在 Android 上的经验,Gradle 总让我觉得很繁琐,而 Ant 是一个不错的构建系统,运行良好,只是似乎更多用于老项目或 legacy 项目。所以 Maven 看起来是最合适的。
Maven 通过命令行工具 mvn 和一个描述项目需求的文件 pom.xml 来使用。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.devbaltasarq</groupId>
<artifactId>frover</artifactId>
<version>1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>25</maven.compiler.source>
<exec.mainClass>com.devbaltasarq.frover.Ppal</exec.mainClass>
</properties>
<name>frover</name>
<description>A simple file manager.</description>
</project>
Manifest 的问题
你开始创建应用并在 NetBeans(例如)中运行它。一切正常,于是决定自己使用(dogfooding)。但是你的 JAR 无法启动。从命令行:
$ mvn package
$ java -jar target/frover-1.0.jar
no main manifest attribute, in frover-1.0.jar
JAR 需要一个名为 MANIFEST.MF 的特殊文本文件,放在 META-INF 目录下。它的最小内容应该是:
Manifest-Version: 1.0
Main-Class: com.devbaltasarq.frover.Ppal
JAR 本质上是 zip 文件。检查它们:
$ unzip -v target/frover-1.0.jar
Archive: target/frover-1.0.jar
...
$ unzip -v target/frover-1.0.jar | grep -i manifest
没有看到 MANIFEST.MF。虽然 pom.xml 已经包含了主类信息(properties.exec.mainClass),Maven 并不会自动生成 manifest。
添加 maven-jar-plugin 插件
为了让 Maven 包含 manifest,需要在 pom.xml 中加入 maven-jar-plugin:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<addMavenDescriptor>true</addMavenDescriptor>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<mainClass>${exec.mainClass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
有了这段配置,Maven 会生成 MANIFEST.MF,生成的 JAR 能正常运行。
完整的 pom.xml
下面展示了包含插件配置的完整 pom.xml:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.devbaltasarq</groupId>
<artifactId>frover</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>25</maven.compiler.source>
<exec.mainClass>com.devbaltasarq.frover.Ppal</exec.mainClass>
</properties>
<name>frover</name>
<description>A simple file manager.</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<addMavenDescriptor>true</addMavenDescriptor>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<mainClass>${exec.mainClass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
结论
配置好 maven-jar-plugin 后,JAR 会包含 manifest 并能够顺利启动。虽然必须添加这么多 XML 有点繁琐,但至少 Maven 让我们可以轻松管理依赖(例如通过在同一个 pom.xml 中加入 Google 的 Gson 库)。开发仍在进行中,随后会为应用添加一个 JSON 配置文件。