Maven给我们的开发工作带来了很大的便利,也增加了项目后期的可维护性,但它同样也很复杂,学习起来比较费劲,特别是一些配置可能很难搞明白。今天在这里主要是按照我们从学习到工作再到平台化开发等这样的需求升级顺序来详细分析一下,我们为什么需要Nexus,为什么需要Mirror,以及它们都应该如何配置。
一、jar包是怎么下载下来的
刚刚接触Maven时,可能我们最先学会的就是配置一下Maven的工作目录以及settings.xml文件,其他的配置可能要用了一段时间之后才学会怎么配置。这时我们应该都有一个疑问,当我们保存pom.xml文件后,jar包为什么就自动下载下来了?
这其实跟pom.xml文件的继承有关,所有的maven项目中的pom.xml都继承了super pom.xml,那么super pom.xml的位置在哪里呢?你可以用解压工具打开位于${MAVEN_HOME}/lib/maven-model-builder-x.x.x.jar,然后访问路径org/apache/maven/model,在这个目录中我们可以看到一个pom-x.x.x.xml的文件,这就是super pom.xml文件。位置如下:
打开这个pom文件我们可以看到在这个pom文件中配置了一个repository,这就是我们下载的jar包所存放的源仓库,它有一个url地址,我们用浏览器可以直接访问到这个地址,为了便于区分,这个仓库还有一个repositoryId 文件内容如下:
当我们在项目中保存pom文件时,由于项目中的pom继承于这个super pom,所以maven会自动去这个*仓库下载我们所需要的jar包,并保存在settings.xml文件配置的本地仓库中,当我们下次使用同样的maven构件时就不需要再去*仓库下载了,它会直接去本地仓库中去查找,如果没有找到它才会去*仓库去下载。
二、为什么需要Mirror以及MirrorOf的作用
在工作中使用Maven时,我们会发现由于Maven默认使用的*仓库地址在国外,网络不好的时候一个jar包半天下载不下来,如果这个时候刚好又急着用的话就很悲催了,所以为了提高jar包的下载速度,我们可以为*仓库配置一个镜像,当需要到*仓库下载jar包时就直接访问这个镜像即可。
可能有的朋友不太明白镜像是什么意思,这里简单说明一下。首先,我们从字面意思理解一下。镜像,意为镜子里面的影像。拿我们平时照镜子来说,镜子中的你,其实就是你的镜像。那么这里我们配置的镜像,是谁的镜像?当然是*仓库的镜像,也就是说我们需要为repositoryId为central的*仓库配置一个镜像来提高jar包的下载速度。它需要在settings.xml中进行配置,下面我们来配置阿里云镜像,示例如下:
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
上面的配置中id是为了唯一标识一个镜像(随便定义,不重复即可);mirrorOf是指当前镜像所代表的*仓库;name相当于是一个镜像说明;url指明了当前镜像的网络地址。这个mirror配置在settings.xml文件的<mirrors></mirrors>标签中,配置好之后,我们再去更改pom文件添加maven构件时,就不会直接访问*仓库了,而是访问阿里云镜像。
我们可以尝试将本地仓库中已经下载的maven构件删除,然后随意在pom文件中打一个空格或换行,重新保存pom文件,观察下载jar包的进程是不是连接到了aliyun,如果是的话再去本地仓库看一下maven构件是否下载成功。
三、为什么需要私服
我们在开发时用到的开源jar包,基本上*仓库中都能找的到,我们可以通过配置repository或者mirror来进行下载使用。但是公司内部不准备开源的基础平台jar包以及合作公司不准备开源的公共平台jar包呢?它们应该怎么提供给需要使用的人进行下载呢?这时我们就需要使用私服了,Nexus是一款比较好用的开源免费的私服产品,使用它我们可以在公司内部网络搭建属于我们自己的内部*仓库。
下载安装请参考:学习笔记(四)—— 在linux下搭建neuxs私服(包含3.0以下和3.0以上两个版本)
发布jar包或添加第三方jar包请参考:Maven学习笔记(四)—— 将本地项目打包发布到私服(nexus)上以及在私服上添加第三方Jar包(ojdbc)
我们配置私服的目的不仅仅是可以将jar包上传到私服,更重要的是可以从私服上下载jar包,我们可以将settings.xml中的mirror配置更改为如下所示:
<mirror>
<id>nexus</id>
<!--*代表匹配所有仓库,它是所有仓库的镜像-->
<mirrorOf>*</mirrorOf>
<name>Central Repository</name>
<url>http://192.168.188.132:8081/nexus/content/groups/public</url>
</mirror>
当我们在settings.xml中配置了私服的mirror时,所有下载jar包的请求都会请求到私服上,我们可以从本地仓库删除一个jar包,然后更改pom文件,保存之后观察下载进程提示,示例如下:
此时,当我们配置了私服之后,下载jar包的流程是这样子的:maven首先会去本地仓库查找jar包,如果没有查找到,它就会去访问*仓库,但由于我们给*仓库配置了镜像,所以它会去访问*仓库的镜像,也就是私服。如果在私服中查找到了需要的jar包,它就会直接下载下来;如果在私服中还是没有查找到,这时它就会去访问*仓库,并从*仓库将jar包下载到私服,然后再从私服下载到本地仓库。
四、仓库,镜像,私服如何结合使用
我们在工作中可能会有这样一个需求,我需要一个私服,当本地没有jar包时去私服下载,当私服没有jar包时我不想让它去*仓库下载,而是想让它去阿里云下载,下载之后保存在私服上,然后再下载到本地,而且当我发布项目到私服时也不受影响。如何实现这个需求?可能有的朋友会想到直接配置两个mirror,一个是阿里云镜像,一个是私服镜像,但真正实现起来发现不是我们想要的效果。下面我们先来看一下Maven的下载模型:
从上图中可以看出来,当我们需要一个jar包时会有两种常用的下载链:
1、下载链1
maven会首先检查本地仓库,本地仓库没有就去查找pom文件中配置的仓库,由于super pom中默认配置了一个*仓库,所以它会直接去*仓库下载。那如果我们配置了自己的远程仓库呢?比如:私服。那么这个时候它会先去查找我们自己配置的私服仓库,如果私服仓库有那么就直接下载到本地仓库,如果私服仓库没有它才会去访问*仓库。也就是说,*仓库是pom文件中配置的仓库列表中查找顺序最后的那一个仓库。
我们可以将settings.xml文件中关于mirror和repository的配置全部注释掉,然后在项目的根pom文件中添加一个私服仓库,私服仓库中发布一个*仓库没有的maven构件,然后再将本地的这个maven构件删除,保存之后开始下载。通过这种方式来验证下载链1是否正确。在根pom中添加仓库的配置如下:
<!--配置私服仓库-->
<repositories>
<repository>
<!--仓库id,repositories可以配置多个仓库,保证id不重复-->
<id>nexus001</id>
<name>nexus repository</name>
<!--仓库地址,即nexus仓库组的地址-->
<url>http://192.168.188.132:8081/nexus/content/groups/public</url>
<!--是否下载releases构件-->
<releases>
<enabled>true</enabled>
</releases>
<!--是否下载snapshots构件-->
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
2、下载链2
当我们在settings.xml中配置了镜像,甚至于在settings.xml中配置了私服仓库,这时maven应该如何工作呢?此时,maven还是会首先去查找本地仓库,如果本地仓库没有的话,它就会去我们自己配置的私服仓库中去找,如果私服仓库中也没有的话,私服就会去*仓库中去查找,由于我们为*仓库配置了阿里云镜像,所以这时它会首先去阿里云镜像查找,如果阿里云镜像也没有的话,它才会去访问*仓库,如果*仓库也找不到,它才会去settings.xml中配置的其他远程仓库中去查找。
我们可以在根pom文件中添加一个私服仓库,然后在settings.xml中添加一个central的阿里云镜像,然后将本地的一个jar包删除,保存之后下载。通过这种方式来验证下载链2是否正确。
通过上面的验证方式验证之后,我们发现本地仓库没有的jar包的确是到阿里云下载了,而且下载之后也保存到了私服上,并从私服下载到了本地。同时,我们在进行项目发布时也可以正常使用。这就实现了我们上面提出的需求。
但这时有一个问题,如果我还有其他项目也有这个需求呢?那是不是意味着每个项目的根pom都要进行这样的仓库配置呢?这出现了重复的问题,我能不能将配置复用呢?能不能将这个仓库配置到settings.xml中进行全局配置呢?经过测试,答案是否定的。因为在上面的maven下载模型中,settings.xml文件中的仓库配置是下载链的最后一步,如果我们只是在settings.xml文件中进行全局配置,那么jar包的确会下载到本地,但jar包不会下载到私服,它不满足我们的需求。当然也可能是我对maven的下载模型理解有误,导致配置错误,如果有更好建议的朋友,欢迎一起探讨!
参考: