maven仓库-nexus实战及踩坑总结
目录
一、nexus基本概念
1、仓库的分类

本地仓库:内部项目的发布仓库。
远程仓库:代理中央仓库或者其他nexus仓库。
3rd仓库: 第三方依赖的仓库。一般是内部开发人员下载后上传到这个仓库。
group仓库组:用来方便用户配置开发环境,settings.xml中直接配置group即具有使用group中添加的多个仓库的权限。
2、包依赖搜索顺序

二、实战问题
1、备份
方案:定时/实时同步整个仓库到备机服务器,备机也安装nexus,需要时启动备机的nexus,变更域名指向即可。实际上启用备机的概率很低,但是备份不可少!服务器之间增量数据同步,我用的Rsync。
2、无法下载jar包
在nexus中能检索到某个jar,但project无法通过pom依赖下载jar。
方案:检查本地仓库中该jar对应的目录下是否存在.lastUpdated结尾的文件,并将其删除,再重新拉取即可。
3、无法deploy
400错误:Return code is: 400
大致有以下几种原因:
1)每个仓库的Repository Policy只能为release或者snapshot,如果将release的jar包上传到snapshot类型的仓库,或者snapshot类型的jar上传到release仓库,则deploy失败。
2)release仓库一般会设置为Disable Redeploy,如果上传坐标相同的jar,则deploy失败。
3)只能deploy到Hosted类型的仓库,若上传到Proxy、Virtual仓库会报400错误。
401错误:Return code is: 401, ReasonPhrase: Unauthorized.
原因:权限错误。检查maven配置,检查是否配置了要上传的仓库及账号密码是否正确。
settings.xml中<server></server>的配置即为要上传的仓库。要deploy到哪个仓库,就要在<server>中配置上对应的仓库id、username、password。
<servers>
<server>
<id>snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>thirdparty</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>releases</id>
<username>admin</username>
<password>admin123</password>
</server>
<!-- 其他仓库-->
</servers>
4、依赖的jar不完整
通俗的解释就是:拉取某个jar时,只能下载其本身,无法下载其自身依赖的其他jar。我们构建一个project并deploy到仓库时,最终上传的是具体的一个构件(jar/war),但是这个project自身可能会依赖其他构件。别人在使用你的jar时,只有同时将所有依赖下载到本地,才能正常使用。
例如:

问题产生原因:该jar包的上传方式错误。
如何正确的上传一个jar?
deploy一个jar,有很多种方式:
-
直接IDE中deploy(适用于内部开发的项目)
-
nexus管理员登录后台上传(适用于上传一个第三方的jar)
-
直接通过mvn deploy命令上传(适用于上传一个第三方的jar)
如果是通过mvn deploy命令上传,需要特别注意一个参数:-DpomFile=$pom_name,如果上传的jar自身依赖了其他jar,需要指定-DpomFile,否则在使用时只能下载该jar本身,无法下载其间接依赖。
完整命令如下:
mvn deploy:deploy-file -Dfile=$jar_name -DgroupId=xxx -DartifactId=xxx -Dversion=xxx -Dpackaging=jar -DrepositoryId=仓库Id -Durl=仓库地址 -DpomFile=$pom_name
pomFile如图(以jedis的包为例):

5、多个nexus合并踩坑
背景:由于历史原因,多个开发部门都搭建一套自己的nexus,后期随着公共组件的推广及项目融合,跨仓库使用jar存在诸多不便,所以,出现了一波统一nexus的操作。
目标:存在nexusA、nexusB/C/D,要统一使用nexusA,下掉nexusB/C/D,所以,需要将nexusB/C/D的jar导入到nexusA,并统一开发者本机及CICD编译机的maven settings配置,最终完成统一。
方案:实施的重点在于jar包导入,导入jar有两种方式
-
方案一、将nexusB的仓库直接拷贝到nexusA的仓库;
-
方案二、在nexusA中创建代理仓库,远程地址配置为nexusB,过渡一段时间,随着应用的重新构建,将nexusB的包都缓存到nexusA之后,再下掉nexusB。(原理:包依赖搜索顺序)
-
方案三、手动将需要的jar上传到nexusA(较适用于量很小的情况)
核心问题:两个nexus中如果出现坐标相同的jar如何处理?
仓库中(host、proxy、thirdParty多个仓库看成一个整体)存在坐标相同jar时,会使用上传时间最新的。考虑复杂的实际情况,如果坐标相同的jar,内容不一样,(例如:内部接口有改动),可能会对原nexusA、nexusB各自的应用造成影响。因此,最保险、最严谨的做法是排除重复后再统一仓库。
踩坑:以A.jar为例,两个nexus都存在A.jar,nexusB的时间最新,对比md5相同,因此当时认为无论用哪个仓库的A.jar都一样,不会对应用造成任何影响。但是,当nexusA创建了nexusB的代理仓库后,原nexusA的应用确实使用了nexusB中的A.jar,虽然md5相同,但A.jar自身依赖的jar却没有拉取下来,导致应用启动失败,报classNotFound的错误。
这个问题主要是由于nexusB仓库使用了错误的方式上传的A.jar,致使在依赖A.jar时未能将其自身依赖拉取下来。
总结:在合并仓库方案、排除重复包的考虑上,我们的思路是对的。但是,忽略的细节是,在nexus中,MD5相同只能说明两个jar的内容一致,不能保证在使用上效果一样,不能保证不会出现上述第四个问题:依赖的jar不完整(jar内部的依赖关系下载,由nexus控制)。
问题发生时的应对策略:
下午合并了nexus仓库,晚上有老应用发版,反馈出现classNotFound问题。当时,第一反应就是有可能和nexus合并有关系,因为maven的settings.xml中配置的是group组而不是具体仓库,所以,将下午配置的远程代理仓库nexusB从group中移除(其实也可以直接删除配置的代理仓库),应用重新发版成功。
以上文字描述可以通过如下图1、图2更直观的看到:
图1:未设置nexusB的代理时,拉取的是nexusA中的jar(jedis为内部重新封装的包,理解意思即可,无需关注包名)

图2:设置nexusB的代理后,拉取的是nexusB中的包。仔细观察,发现未拉取到jedis自身依赖的commons-lang.jar、commons-pool.jar。(原因应该是nexusB的用户在上传包时上传方式错误)

总结:
在合并仓库方案、排除重复包的考虑上,我们的思路是对的、是严谨的。但是,忽略的细节是,在nexus中,MD5相同只能说明两个jar的内容一致,不能保证在使用上效果一样,不能保证间接依赖完全下载的问题。
更多推荐
所有评论(0)