经验之谈
工作中,我们常常需要将基础架构部门的 jar 包提供给业务部门的同事使用,那么,需要将 jar 包 deploy 到 nexus 私服上,网上资料不是很多,这里说一下具体细节。
首先,是打 jar 包,maven 默认是不会将依赖的 jar 打入到新包中的,而是通过 pom 文件进行构建。而现在流行的 SpringBoot 项目则将所有的 jar 包打进去,使其能够快速部署。
通常,我们上传到 Nexus 私服上的 jar 包不会包含其他的 jar 包,依赖关系依靠 pom 文件。
假设,你已经通过 package 命令生成了一个不包含其他的 jar 的 jar 包。那么就可以使用以下命令:
mvn deploy:deploy-file -DgroupId={yourProject} \ -DartifactId={yourProject}\ -Dfile={yourFile}\ // jar 包路径-Durl={URL} \// 私服URL-DrepositoryId=releases\ -Dpackaging=jar\ // 指定格式,如果不写,一句 pom 文件中-DpomFile=pom.xml // 指定该 jar 包的 pom 文件,如不指定,将生成一个默认的 pom——导致不可用
其中,比较关键的就是 -DpomFile=pom.xml
,如果你不指定的话,那么 maven 就会自动生成一个 pom ,但基本是一个空的 pom,依赖关系都没有的 —— 这将导致,如果别人引用了你的 jar 包,并且需要使用依赖关系里的代码,但却找不到,就会抛出 NoClassDefFoundError 错误,因为编译时没有问题,但运行时却找不到 class 文件。
deploy:deploy-file 插件有很多参数,想了解更多内容,可以参照官方文档:https://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html#packaging。
意外收获
关于 NoClassDefFoundError 和 ClassNotFoundException 的区别,因为查错的时候,遇到了这个错误,所以查了一下:
前者是编译成功,但运行时找不到 jar 包,通常是两个相同的类,不同的版本,或者我上面的说的,jar 包里没有依赖包,pom 里也没有依赖关系,并且,相关的类也会 import 这个类。
后者通常发生在使用反射时,例如
Class.forName("cn.thinkinjava.Hello")
,反射的时候,是不会 import 这个类的,两者的错误场景是不一样的。
从后者是个异常,前者是个 error 就能看出,Java 容忍前者,不容忍后者,前者更多的是构建过程中的错误,而不是编码过程中的错误,