maven 打的包在哪_maven打包流程学习「建议收藏」

2022-08-26 13:51:32 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

前言:

最近工作中遇到了几次跟maven打包相关的问题,每个问题上网查资料解决都花了不少时间,很影响工作进度。既然遇到好几次,每次都能发现知识盲点,干脆总结整理一下,啃掉这个难啃的骨头。

ps:最近看到了一个很有意思句子:因为今天不想跑步,所以才去跑,这是长距离跑者的思维方式。

转载:

正文:

还是首先描述一下最近遇到的几个问题吧:

一、初见

springboot多模块项目mvn打包遇到的问题 – 存在依赖但却无法发现符号

这个描述跟我遇到的问题差不多,简单说就是AB两个工程是同一个父工程(X)下的子工程,因为A是一个springboot项目,所以父工程X就把parent设置成了:

org.springframework.boot

spring-boot-starter-parent

2.0.1.RELEASE

并且在A项目中配置了打包插件:

org.springframework.boot

spring-boot-maven-plugin

true

然后AB的都是X。另一个同事开发A,在里边写了一个XXXUtil类。我开发B,为了使用XXXUtil,于是在B的dependency里依赖了A。

本地测试正常,然后就打算mvn install一下,结果就报错:

[INFO] ————————————————————————

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project main-jar: Compilation failure: Compilation failure:

[ERROR] /Users/zhaohui/workspace/Projects/IDEA/packing-test/main-jar/src/main/java/com.zh/Main.java:[3,25] 程序包com.zh.sbt.common不存在

[ERROR] /Users/zhaohui/workspace/Projects/IDEA/packing-test/main-jar/src/main/java/com.zh/Main.java:[8,51] 找不到符号

[ERROR] 符号: 变量 Common2

[ERROR] 位置: 类 com.zh.Main

[ERROR] -> [Help 1]

[ERROR]

奇怪了,测试的时候明明可以,怎么打包的时候就找不到类了呢?于是就打开A项目打出来打jar包,看一下里边是不是真的没有这个类:

zhaohuideMacBook-Pro:target zhaohui$ jar vtf spring-boot-test-1.0-SNAPSHOT.jar

…//此处省略部分输出

350 Thu Feb 28 23:15:32 CST 2019 BOOT-INF/classes/com/zh/sbt/common/Common2.class

347 Thu Feb 28 23:15:32 CST 2019 BOOT-INF/classes/com/zh/sbt/common/Common.class

822 Thu Feb 28 23:15:32 CST 2019 BOOT-INF/classes/com/zh/sbt/Main.class

…//此处省略部分输出

发现,包内的文件夹路径跟我项目的文件夹路径不一致,用luyten-0.5.3反编译代码,发现代码里的package行没有变化,所以springboot有可能使用了自定义的类加载器,把类加载器的根目录设置为了BOOT-INF/classes/,而maven打包的时候,使用的类加载器根目录就是项目根路径,所以才找不到类。

既然是A项目打包的问题,那直接把A项目的标签注释掉不就行了。说干就干,修改完果然可以正常打包了。

然后就是提交代码,部署,结果A项目启动不起来了,报错如下:

zhaohuideMacBook-Pro:target zhaohui$ java -jar spring-boot-test-1.0-SNAPSHOT.jar

spring-boot-test-1.0-SNAPSHOT.jar中没有主清单属性

其实到这里思路已经比较混乱了,为什么spring-boot的打包插件能修改文件路径?为什么不用spring-boot插件就找不到主属性清单?应该用什么打包插件呢?有哪些打包插件呢?每个插件有什么区别呢?

今天太累了,我不想跑步了。。。

面对这么多疑问,大概就是这个感觉。具体怎么解决暂且不表,第一次遇到这个问题,也没有想明白这么多疑问,结果没想到,第二天,又遇到了打包的问题,而且这次的问题更让我郁闷。且听我慢慢道来… …

二、重逢

接下来就说说我的B项目,因为项目的任务是通过程序往hadoop集群提交一个mr任务,B项目的代码特别简单,就是调用yarn的api提交一个任务。

本地测试也没有问题,我就想把代码放到线上跑一下。因为jar包需要很多依赖,就想着直接把所有的依赖都打到一个jar文件里,这样就不用上传一堆依赖jar包了。于是我使用了这个打包插件:

org.apache.maven.plugins

maven-shade-plugin

3.1.1

package

shade

implementation=”org.apache.maven.plugins.shade.resource.ManifestResourceTransformer”>

com.zh.Main

有了昨天的经验,在plugin里边配置里主类,应该没有问题吧,于是执行了一下jar包,然后就报了一个奇怪的错误:

[WARN ] 2019-02-28 23:59:26 [main] o.a.hadoop.util.NativeCodeLoader – Unable to load native-hadoop library for your platform… using builtin-java classes where applicable

[ERROR] 2019-02-28 23:59:26 [main] c.k.dp.dataexchange.manager.Main – Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name and the correspond server addresses.

java.io.IOException: Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name and the correspond server addresses.

at org.apache.hadoop.mapreduce.Cluster.initialize(Cluster.java:120)

at org.apache.hadoop.mapreduce.Cluster.(Cluster.java:82)

at org.apache.hadoop.mapreduce.Cluster.(Cluster.java:75)

at org.apache.hadoop.mapreduce.Job$9.run(Job.java:1260)

at org.apache.hadoop.mapreduce.Job$9.run(Job.java:1256)

at java.security.AccessController.doPrivileged(Native Method)

at javax.security.auth.Subject.doAs(Subject.java:422)

at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657)

at org.apache.hadoop.mapreduce.Job.connect(Job.java:1255)

at org.apache.hadoop.mapreduce.Job.submit(Job.java:1284)

at com.kuaishou.dp.dataexchange.manager.Main.main(Main.java:95)

Exception in thread “main” java.lang.RuntimeException: 集群启动发生异常,异常信息Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name and the correspond server addresses.

at com.kuaishou.dp.dataexchange.manager.Main.main(Main.java:102)

这报错信息是什么鬼。。。说明内容一点都不具体,看不懂,只能找到报错的代码:

private void initialize(InetSocketAddress jobTrackAddr, Configuration conf) throws IOException {

ServiceLoader var3 = frameworkLoader;

synchronized(frameworkLoader) {

Iterator i$ = frameworkLoader.iterator();

while(i$.hasNext()) {

ClientProtocolProvider provider = (ClientProtocolProvider)i$.next();

LOG.debug(“Trying ClientProtocolProvider : ” provider.getClass().getName());

ClientProtocol clientProtocol = null;

try {

if (jobTrackAddr == null) {

clientProtocol = provider.create(conf);

} else {

clientProtocol = provider.create(jobTrackAddr, conf);

}

if (clientProtocol == null) {

LOG.debug(“Cannot pick ” provider.getClass().getName() ” as the ClientProtocolProvider – returned null protocol”);

} else {

this.clientProtocolProvider = provider;

this.client = clientProtocol;

LOG.debug(“Picked ” provider.getClass().getName() ” as the ClientProtocolProvider”);

break;

}

} catch (Exception var9) {

LOG.info(“Failed to use ” provider.getClass().getName() ” due to error: “, var9);

}

}

}

if (null == this.clientProtocolProvider || null == this.client) {

throw new IOException(“Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name and the correspond server addresses.”);

}

}

先是debug,打断点,发现不打包执行没有问题,这就比较蛋疼了,排查问题都不好排查。还好有一些debug的日志可以参考。于是执行参数增加 -Xdebug,logback日志级别改成DEBUG,再次执行jar包,中间细节不再赘述,总之找到出问题的代码在这里:

//java.util.ServiceLoader line 338 hasNextService()方法//代码逻辑简单说就是Enumeration configs = ClassLoader.getSystemResources(“META-INF/services/” ClientProtocolProvider.class.getName());

//如果不打包,获取到的configs size为2,打印出来就是://org.apache.hadoop.mapred.LocalClientProtocolProvider//org.apache.hadoop.mapred.YarnClientProtocolProvider//如果打包,获取到的configs size为1,打印出来就是://org.apache.hadoop.mapred.LocalClientProtocolProvider

搞了半天,打包修改了META-INF/services/里的内容,所以才导致了报错。

ps:吐槽一下hadoop报错信息,完全没有描述出错的问题,导致排查浪费了很多时间。

说实话,解决这个问题,并没有很开心,一方面花了太多时间,另一方面,这次的问题给我带来了更多的困扰:META-INF里边n多东西都是干什么的?打包的时候如何处理META-INF这个文件夹?

最让我奇怪的是,我总共就配置了一个plugin,结果target里边打出来了三个包[xxx.jarxxx-shade.jarxxx-source.jar]除了shade以外,其他两个jar为什么会打出来呢?

三、回首

打包给自己的工作带来了这么多困扰,归根结底还是不知道maven到底是怎么打包的,所以遇到了具体的问题就不知道该怎么分析解决。所以这次正好整理了一下思路。虽然没有给出上边问题的具体解决方式,但是能够把思路说明白,后续再慢慢分析解决问题吧。

思考这个问题的入口其实就是maven的这个标签,具体配置在里边的东西都起到了什么作用呢?很幸运的找到了这篇文章maven内部运行原理解析

具体细节我就不描述了,看到这里,我的疑问是,文章中提到,每一个plugin,都要有一个和表明该插件是在哪个阶段执行的哪个方法。我的pom里边并没有配置这些,插件也照样能生效,那我怎么知道具体每个插件的这两个配置项呢?另外如果我一个plugin都没有配置,也正常打包了,这个时候使用的是什么配置呢?

在maven中,所有的PO都有一个根对象,就是Super POM。Super POM中定义了所有的默认的配置项。Super POM对应的pom.xml文件可以在maven安装目录下lib/maven-model-builder-3.0.3.jar:org/apache/maven/model/pom-4.0.0.xml中找到

第一个问题我在这个帖子里找到了解决的方法maven常用插件解析 :

maven-help-plugin

maven-help-plugin是一个小巧的辅助工具。

最简单的help:system可以打印所有可用的环境变量和Java系统属性。

help:effective-pom和help:effective-settings最为有用,它们分别打印项目的有效POM和有效settings,有效POM是指合并了所有父POM(包括Super POM)后的XML,

当你不确定POM的某些信息从何而来时,就可以查看有效POM。

有效settings同理,特别是当你发现自己配置的settings.xml没有生效时,就可以用help:effective-settings来验证。

此外,maven-help-plugin的describe目标可以帮助你描述任何一个Maven插件的信息,还有all-profiles目标和active-profiles目标帮助查看项目的Profile。

所以执行mvn help:effective-pom就可以列出所有的配置项,我对空项目执行了一下这个命令,把默认的所有插件整理了一下,总结如下:

//知乎怎么还不支持表格

| parse | plugin | goal |

| —— | —— | —— |

| clean | maven-clean-plugin | clean |

| process-test-resources | maven-resources-plugin | testResources |

| process-resources | maven-resources-plugin | resources |

| package | maven-jar-plugin | jar |

| compile | maven-compiler-plugin | compile |

| test-compile | maven-compiler-plugin | test-compile |

| test | maven-surefire-plugin | test |

| install | maven-install-plugin | install |

| deploy | maven-deploy-plugin | deploy |

| site | maven-site-plugin | site |

| site-deploy | maven-site-plugin | deploy |

这里出现了maven内部运行原理解析中没有提到的几个parse:[clean/site/site-deploy]这几个的含义在这个帖子找到了答案:maven的三大生命周期

现在知道了具体每个阶段执行的是哪个方法,剩下的只要获取插件的代码就能完整的分析整个打包流程了,代码地址:查看maven插件的源码

至此,整个思路就理清楚了。即使没有把这块硬骨头啃下来,至少已经放进锅里了~~

附录:

最开始查资料的时候,没有搞清楚打包和压缩是两件事,查了一些与压缩相关的内容,其中这个帖子很有意思:RAR和ZIP:压缩大战真相

向菲利普·卡兹致敬!!

总结:

最近工作接触了很多新东西,也遇到了各种个样的问题。天天一边解决问题,还要赶项目进度,每天都要搞到很晚,每当要开始整理一些东西的时候,总是想着:今天太累了,不搞了吧,早点休息养精蓄锐,明天总结。结果天天如此,一拖就是一个月。

因为今天不想跑步,所以才去跑,这是长距离跑者的思维方式。

而我想成为长距离跑者!

以上

最后,让我们保持独立思考,不卑不亢。长成自己想要的样子! (引用自 我非常喜欢的B站up主 ”独立菌儿“->猛戳链接

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/144013.html原文链接:https://javaforall.cn

0 人点赞