我正在尝试使用 Maven 创建一个 fat jar。每个人都说 Shade 插件是最简单的方法,所以这就是我正在尝试的。我已经尝试了很多示例项目。它们在使用的 XML 标签和 XML 的嵌套方式上都略有不同,这令人困惑和沮丧,但它们都对我不起作用,而且它们都太晦涩了,我无法说出它们为什么不起作用。
我试图将问题归结为最小可行的 Hello World 项目。
这里是项目结构:
├── pom.xml
└── src
└── main
└── java
└── org
└── example
└── Hello.java
我的 Hello.java 看起来像这样:
package org.example;
import gnu.getopt.Getopt;
public class Hello {
public static void main(String[] args) {
Getopt g = new Getopt("hello", args, "x");
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 'x' -> System.out.println("Hello X!");
default -> System.out.println("Error " + c);
}
}
System.out.println("Goodbye");
}
};
我的 pom.xml 看起来像这样:
<?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>org.example</groupId>
<artifactId>hello-fat-jar</artifactId>
<version>0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/gnu.getopt/java-getopt -->
<dependency>
<groupId>gnu.getopt</groupId>
<artifactId>java-getopt</artifactId>
<version>1.0.13</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">i
<mainClass>org.example.Hello</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
到目前为止一切顺利。我做一个 mvn clean package:
$ mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< org.example:hello-fat-jar >----------------------
[INFO] Building hello-fat-jar 0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from central: https://repo.maven.apache.org/maven2/gnu/getopt/java-getopt/1.0.13/java-getopt-1.0.13.pom
Downloaded from central: https://repo.maven.apache.org/maven2/gnu/getopt/java-getopt/1.0.13/java-getopt-1.0.13.pom (2.0 kB at 9.5 kB/s)
Downloading from central: https://repo.maven.apache.org/maven2/gnu/getopt/java-getopt/1.0.13/java-getopt-1.0.13.jar
Downloaded from central: https://repo.maven.apache.org/maven2/gnu/getopt/java-getopt/1.0.13/java-getopt-1.0.13.jar (60 kB at 1.8 MB/s)
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ hello-fat-jar ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-fat-jar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory HOME/src/java/hello-fat-jar/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello-fat-jar ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to HOME/src/java/hello-fat-jar/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-fat-jar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory HOME/src/java/hello-fat-jar/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello-fat-jar ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello-fat-jar ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-fat-jar ---
[INFO] Building jar: HOME/src/java/hello-fat-jar/target/hello-fat-jar-0.1-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.595 s
[INFO] Finished at: 2023-03-24T16:30:35-07:00
[INFO] ------------------------------------------------------------------------
可以看到依赖已经下载好了:
$ ls ~/.m2/repository/gnu/getopt/java-getopt/1.0.13
java-getopt-1.0.13.jar java-getopt-1.0.13.jar.sha1 java-getopt-1.0.13.pom java-getopt-1.0.13.pom.sha1 _remote.repositories
但是它并没有创建一个fat jar:
$ jar tf target/hello-fat-jar-0.1-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
org/
org/example/
org/example/Hello.class
META-INF/maven/
META-INF/maven/org.example/
META-INF/maven/org.example/hello-fat-jar/
META-INF/maven/org.example/hello-fat-jar/pom.xml
META-INF/maven/org.example/hello-fat-jar/pom.properties
当我尝试运行它时,它抱怨没有主要的清单属性,据说 shade 插件应该设置:
$ java -jar target/hello-fat-jar-0.1-SNAPSHOT.jar
no main manifest attribute, in target/hello-fat-jar-0.1-SNAPSHOT.jar
我可以通过添加带有
maven-jar-plugin
的 <mainClass>
来绕过主清单,但它仍然不是一个胖罐子并且找不到 Getopt 依赖项。阴影插件也应该设置主类,但它没有这样做。我想了解为什么它不起作用,并修复它,而不是依赖一个破旧的创可贴。
但是代码和jar还是不错的!我可以使用显式类路径运行它:
$ java -cp target/hello-fat-jar-0.1-SNAPSHOT.jar:$HOME/.m2/repository/gnu/getopt/java-getopt/1.0.13/java-getopt-1.0.13.jar org.example.Hello -x
Hello X!
Goodbye
(不管它值多少钱,这是我能找到的最简洁的教程:https://javahelps.com/how-to-create-a-fat-jar-using-maven)
我做错了什么?我如何使用 shade 插件创建一个 fat jar?
更新:根据 tgdavies 的评论,我删除了
<pluginManagement>
标签,一切都按预期进行。 (插件管理来自 maven archetype:generate
目标。)