java maven-plugin-shade插件 Maven生成的jar运行出现“没有主清单属性”
2023-04-15 16:48 youxin 阅读(599) 评论(0) 编辑 收藏 举报命令窗口运行jar,提示“没有主清单属性”
2.1 分析问题
在打包构建的jar目录内,可以看到有一个MANIFEST.MF文件,如图所示:
该文件就是jar运行时要查找的清单目录,其中主清单数据,就是我们要运行的主类(函数入口main所在的类);
提示缺少主清单属性,就是文件中少了主清单属性如下所示:
正常情况下,该清单文件内会有一个:
Main-Class:org.example.xxx.APP
属性,他就是我们程序运行的入口(main函数所在的类路径)
若想执行Main2则输入java -cp mutimain-1.0-SNAPSHOT.jar Main2
;若想执行Main3,则输入java -cp mutimain-1.0-SNAPSHOT.jar s.Main3
。最后一项参数是主类完整包名
解决问题
通过压缩工具解压我们的jar包,找到清单目录文件,编辑MANIFEST.MF文件:
Manifest-Version: 1.0
Built-By: xiayutian
Created-By: Apache Maven 3.5.0
Build-Jdk: 1.8.0_191
Main-Class: org.example.Platform # 添加上我们的主类路径
将MANIFEST.MF重新替换掉jar包内的文件,问题解决;
另外办法:通过maven-shade-plugin插件
要创建一个可执行的JAR,只需要设置主类作为应用程序的入口点
在maven工程中,pom.xml添加一下插件片段,用来设置主类。
https://maven.apache.org/plugins/maven-shade-plugin/examples/executable-jar.html链接
————————————————
原文链接:https://blog.csdn.net/u012637358/article/details/113996771
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.sonatype.haven.HavenCli</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
<mainClass>tools.A</mainClass> 这里要 `tools.A` 是默认的一个main方法的类完整名(包名.类型)
如何启动
1.执行默认的main()方法
也就是上面tools.A中的main方法
那么就是java -jar xxxxxxx.jar
他就会执行 A类中的main方法
2.手动指定某个类的main()方法
-jar 换成-cp 然后.jar 后面要指定完整类路径(包.类)
如果要执行B中的main方法:java -cp xxxxx.jar tools.B
如果要执行A中的main方法:java -cp xxxxx.jar tools.A
如果要执行C中的main方法:java -cp xxxxx.jar tools.C
maven-plugin-shade 插件提供了两个能力:
把整个项目(包含它的依赖)都打包到一个 “uber-jar” 中
shade - 即重命名某些依赖的包
由此引出了两个问题:
什么是 uber-jar ?
uber-jar 也叫做 fat-jar 或者 jar-with-dependencies,意思就是包含依赖的 jar。
什么是 shade ?
shade 意为遮挡,在此处可以理解为对依赖的 jar 包的重定向(主要通过重命名的方式)。
maven-plugin-shade 必须和 Maven 构建生命周期中的 package 阶段绑定,也就是说,当执行 mvn package 时会自动触发 shade。
原文链接:https://blog.csdn.net/u011441473/article/details/127844885
fat-jar术语解读
术语概念
fat-jar,也被称为uber-jar,是一种特定方式的Jar包。根据ImageJ网站上对于fat-jar的解释(具体见下面引用的英文),从fat-jar的另外一个别名 JAR with dependencies中可以大致窥见这个术语的含义。
对于jar包的格式不太了解的同学可以先了解一下jar文件的格式,通常情况之下jar包用来存储编译好的class文件和resources文件。如果java工程当中依赖于第三方库,那么仅仅打包本项目中编译好的class和resources而成的jar包无法直接运行,仍然需要额外的依赖和引入第三方包。fat-jar就是将依赖的第三方库也打包放入已经编译好的jar中,形成一个“All-in-one”的不需要依赖其他任何第三方包可独立运行部署的jar。
An uber-JAR—also known as a fat JAR or JAR with dependencies—is a JAR file that contains not only a Java program, but embeds its dependencies as well. This means that the JAR functions as an "all-in-one" distribution of the software, without needing any other Java code. (You still need a Java runtime, and an underlying operating system, of course.)
术语由来
Über
在德语中是above
和over
的含义(甚至如果追根溯,它和英文单词over
同源。所以uber-jar直接使用英文翻译就是over-jar
,也就是在jar中额外添加一些其他的文件(这种额外的文件实际上就是上面说到的依赖的第三方库等)。参考自以下资料
Über
is the German word forabove
orover
(it's actually cognate with the Englishover
).Hence, in this context, an uber-jar is an "over-jar", one level up from a simple JAR (a), defined as one that contains both your package and all its dependencies in one single JAR file. The name can be thought to come from the same stable as ultrageek, superman, hyperspace, and metadata, which all have similar meanings of "beyond the normal".
The advantage is that you can distribute your uber-jar and not care at all whether or not dependencies are installed at the destination, as your uber-jar actually has no dependencies.
All the dependencies of your own stuff within the uber-jar are also within that uber-jar. As are all dependencies of those dependencies. And so on.
相关概念
在java应用的开发完成之后,后续的工作就是将这个应用打包并部署到服务器上运行。这里存在好几种打包的方式,一起来研究一下除开今天的主角fat-jar,还有以下的一些打包的概念,此处参考文章The Skinny on Fat, Thin, Hollow, and Uber - DZone Java
- Skinny – Contains ONLY the bits you literally type into your code editor, and NOTHING else.
- Thin – Contains all of the above PLUS the app’s direct dependencies of your app (db drivers, utility libraries, etc).
- Hollow – The inverse of Thin – Contains only the bits needed to run your app but does NOT contain the app itself. Basically a pre-packaged “app server” to which you can later deploy your app, in the same style as traditional Java EE app servers, but with important differences, we’ll get to later.
- Fat/Uber – Contains the bit you literally write yourself PLUS the direct dependencies of your app PLUS the bits needed to run your app “on its own”.
以上的描述可能比较让人摸不着头脑,可以通过一张图来了解上述四种打包方式的关系——
使用场景
springBoot就是使用这样的fat-jar的技术进行打包,将所有的依赖打进一个jar中实现一个All-in-one的jar包。
https://blog.csdn.net/qq_34595352/article/details/119948031
maven-shade-plugin入门指南
有时候,需要将复杂的项目, 包括各种xml文件属性文件, 类, jar等等打包到一个可以执行的jar包中, 然后用java -jar xxx.jar 来运行项目, 这样简单方便, 特别是在编写一些测试工具时,尤为重要。
但是经常发现打包后的项目无法启动, 其中一大类是您项目有问题, 但是这个相对好解决, 毕竟自己的项目可以在windows下的ide中做各种调试,测试都测试好了, 在打包一般程序问题的概率就低得多了。
1. Why?
uber-jar 即为 super-jar,super为关键字,故取名为uber
通过 maven-shade-plugin 生成一个 uber-jar,它包含所有的依赖 jar 包
2. Goals
Goal | Description |
---|---|
shade:help | Display help information on maven-shade-plugin.Callmvn shade:help -Ddetail=true -Dgoal=to display parameter details. |
shade:shade | Mojo that performs shading delegating to the Shader component. |
3. Usage
- 配置 maven-shade-plugin
maven-shade-plugin 将 goal shade:shade 绑定到 phase package 上。
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.3</version> <configuration> <!-- put your configurations here --> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
- 执行命令
mvn clean package
会在 target 文件生成一个 uber-jar,以 -shaded.jar 为后缀的 jar 包。
4. Examples
- Selecting Contents for Uber JAR
将该工程依赖的部分 Jar 包 include/exclude 掉。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>classworlds:classworlds</exclude>
<exclude>junit:junit</exclude>
<exclude>jmock:*</exclude>
<exclude>*:xml-apis</exclude>
<exclude>org.apache.maven:lib:tests</exclude>
<exclude>log4j:log4j:jar:</exclude>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
将依赖的某个 Jar 包内部的类或者资源 include/exclude 掉。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/framework/**</include>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/experimental/**</exclude>
<exclude>org/junit/runners/**</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
maven-shade-plugin 自动将所有不使用的类全部排除掉,将 uber-jar 最小化。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- Attaching the Shaded Artifact
默认会生成一个Jar包和一个以 “-shaded”为结尾的uber-jar包,可以通过配置来指定uber-jar的后缀名。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>jackofall</shadedClassifierName> <!-- Any name that makes sense -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- Executable JAR
通过设置 MainClass 创建一个可执行 Jar 包。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.sonatype.haven.HavenCli</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- Relocating Classes
Java 工程经常会遇到第三方 Jar 包冲突,使用 maven shade plugin 解决 jar 或类的多版本冲突。 maven-shade-plugin 在打包时,可以将项目中依赖的 jar 包中的一些类文件打包到项目构建生成的 jar 包中,在打包的时候把类重命名。下面的配置将 org.codehaus.plexus.util jar 包重命名为 org.shaded.plexus.util。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.codehaus.plexus.util</pattern>
<shadedPattern>org.shaded.plexus.util</shadedPattern>
<excludes>
<exclude>org.codehaus.plexus.util.xml.Xpp3Dom</exclude>
<exclude>org.codehaus.plexus.util.xml.pull.*</exclude>
</excludes>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 31
下面的部分介绍的更为细致些, 特别是, jar包和类的剔除等
https://blog.csdn.net/qq_34595352/article/details/119948031
sprint boot如果找不到main,可以修改
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <mainClass>com.power.CrbDockApplication</mainClass> <includeSystemScope>true</includeSystemScope> </configuration> </plugin>