记一次 Maven 打包后,第三方无法使用的排查记录

731次阅读  |  发布于2年以前

本文主要内容如下:

目录

前言

最近遇到一个需求:

写一个工具类的 JAR 包,然后提供给第三方调用其中的类方法。(前提:第三方无法共用我们项目的私有仓库)

期间遇到了一些问题:

本篇做个记录,希望能帮助到其他小伙伴。

本篇既然涉及到 Maven,这里先总结下 Maven 的常用命令。对 Maven 命令比较熟悉的同学可以跳过这小节。

一、Maven 常见命令

当我们创建好一个 Maven 工程时,IDEA 开发工具的右侧就会自动出现 Maven 命令。

Maven 操作

我们用鼠标双击下就可以运行了,也可以通过命令行来执行

下面介绍这几种命令的区别。

clean(常用)

删除项目路径下的 target 文件,但是不会删除本地的maven仓库已经生成的 JAR 文件。

validate

验证工程正确性,所需信息是否完整。

compile

编译。会在你的项目路径下生成一个target目录,在该目录中包含一个classes文件夹,里面全是生成的class文件。

test

执行单元测试。

package(常用)

将工程文件打包为指定的格式,例如 JAR,WAR 等(看你项目的 pom文件,里面packaging 标签就是来指定打包类型的)。

这个命令会在你的项目路径下一个target目录,并且拥有compile命令的功能进行编译,同时会在target目录下生成项目的 jar/war文件。

如果a项目依赖于b项目,打包b项目时,只会打包到b项目下target下,编译a项目时就会报错,因为找不到所依赖的b项目,说明a项目在本地仓库是没有找到它所依赖的b项目,这时就用到 install 命令。

verify

核实,主要是对 package 检查是否有效、符合标准。

install(常用)

将包安装至本地仓库,以让其它项目依赖。

该命令包含了 package 命令功能,不但会在项目路径下生成 class 文件和 jar 包,同时会在你的本地maven仓库生成 jar 文件,供其他项目使用(如果没有设置过maven本地仓库,一般在用户 /.m2 目录下。如果 a 项目依赖于 b 项目,那么 install b 项目时,会在本地仓库同时生成 pom 文件和 jar文件,解决了上面打包 package出错的问题)。

build

建造。功能类似compile,区别是对整个项目进行编译。

与 compile区别及特点:是对整个工程进行彻底的重新编译,而不管是否已经编译过。

Build过程往往会生成发布包,这个具体要看对 IDE 的配置了,Build在实际中应用很少,因为开发时候基本上不用,发布生产时候一般都用ANT等工具来发布。Build 因为要全部编译,还要执行打包等额外工 作,因此时间较长。

site

生成项目的站点文档。

deploy(常用)

部署。将 jar 包部署到远程仓库,通常是私有仓库。而且包含了 install 命令的功能。

二、打包后,无法 import?

下面介绍一下我用常规打包方式遇到的问题。

我通过 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 不报错了。

但是又报另外一个错,我们接着往下看。

三、缺少其他 Jar 包依赖?

报错信息如下:

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