本文主要内容如下:
目录
最近遇到一个需求:
写一个工具类的 JAR 包,然后提供给第三方调用其中的类方法。(前提:第三方无法共用我们项目的私有仓库)
期间遇到了一些问题:
本篇做个记录,希望能帮助到其他小伙伴。
本篇既然涉及到 Maven,这里先总结下 Maven 的常用命令。对 Maven 命令比较熟悉的同学可以跳过这小节。
当我们创建好一个 Maven 工程时,IDEA 开发工具的右侧就会自动出现 Maven 命令。
Maven 操作
我们用鼠标双击下就可以运行了,也可以通过命令行来执行
下面介绍这几种命令的区别。
删除项目路径下的 target 文件,但是不会删除本地的maven仓库已经生成的 JAR 文件。
验证工程正确性,所需信息是否完整。
编译。会在你的项目路径下生成一个target目录,在该目录中包含一个classes文件夹,里面全是生成的class文件。
执行单元测试。
将工程文件打包为指定的格式,例如 JAR,WAR 等(看你项目的 pom文件,里面packaging 标签就是来指定打包类型的)。
这个命令会在你的项目路径下一个target目录,并且拥有compile命令的功能进行编译,同时会在target目录下生成项目的 jar/war文件。
如果a项目依赖于b项目,打包b项目时,只会打包到b项目下target下,编译a项目时就会报错,因为找不到所依赖的b项目,说明a项目在本地仓库是没有找到它所依赖的b项目,这时就用到 install 命令。
核实,主要是对 package 检查是否有效、符合标准。
将包安装至本地仓库,以让其它项目依赖。
该命令包含了 package 命令功能,不但会在项目路径下生成 class 文件和 jar 包,同时会在你的本地maven仓库生成 jar 文件,供其他项目使用(如果没有设置过maven本地仓库,一般在用户 /.m2 目录下。如果 a 项目依赖于 b 项目,那么 install b 项目时,会在本地仓库同时生成 pom 文件和 jar文件,解决了上面打包 package出错的问题)。
建造。功能类似compile,区别是对整个项目进行编译。
与 compile区别及特点:是对整个工程进行彻底的重新编译,而不管是否已经编译过。
Build过程往往会生成发布包,这个具体要看对 IDE 的配置了,Build在实际中应用很少,因为开发时候基本上不用,发布生产时候一般都用ANT等工具来发布。Build 因为要全部编译,还要执行打包等额外工 作,因此时间较长。
生成项目的站点文档。
部署。将 jar 包部署到远程仓库,通常是私有仓库。而且包含了 install 命令的功能。
下面介绍一下我用常规打包方式遇到的问题。
我通过 IDEA 工具创建了一个 SpringBoot 项目,然后 pom.xml 文件中会自动引入一个打包插件,如下图所示:
然后我执行 maven package 命令,会在项目的 target 目录生成一个 JAR 包。如下图所示:
然后我做了以下事情:
scope 指定为 system,表示引入指定路径(systemPath配置)下的 JAR 包。
看起来这么做没问题了,但是当我们 import 这个 JAR 包下的类时,就会报错。如下图所示:
很奇怪,这里为什么会报错呢??
先看下这个 JAR 包是否引入了。如下所示,可以看到确实是正确引入了,没有报错。
通过 research,发现这个打包插件打出来的 JAR 包,是供执行的,也就是可以通过 java -jar 命令来运行这个 JAR 包,并不能给第三方来引用使用。
解决方案:换一个打包插件 maven-compiler-plugin
。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
再次打包发给第三方,发现 import 不报错了。
但是又报另外一个错,我们接着往下看。
报错信息如下:
java.lang.NoClassDefFoundError: org/apache/commons/codec/binary/Base64
通过这个信息,可以想到是不是我提供的 JAR 包中引入了这个 commons-codec 依赖,而 JAR 包文件中又不包含这个依赖。
看下这个 JAR 文件的大小,只有 14 KB, 而 commons-codec 的包大小为 339 KB,说明这个 JAR 包确实不包含 common-codec 依赖。
解决方案:
那如何将依赖的包打进这个 JAR 包里面呢?
这里还要引入一个打包插件:maven-assembly-plugin,如下所示。(省略了部分标签)
<!--添加依赖 maven-assembly-plugin -->
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
</dependency>
<!--添加插件 maven-assembly-plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<!--打包时,包含所有依赖的jar包-->
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
然后还要用插件打包的方式:assembly:assembly
然后target目录下会多出一个包,带了一个后缀:jar-with-dependencies
decryption-0.0.1-SNAPSHOT-jar-with-dependencies.jar
这个包的文件的大小比较大,有 15.4 M。
发给第三方再次引入后,不再报错了。
我们来看下这个包里面有什么东西,在 META-INF/maven 目录下可以看到 commons-codec 依赖包,说明确实将这个依赖包打进去了。
而之前打的包,是没有这个目录的。
至此,排查结束。
参考资料:
https://blog.csdn.net/Shangxingya/article/details/114810454
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8