maven系列(五)仓库(有todo)
仓库
什么是maven仓库
任何一个构件都有一组坐标唯一标识。
得益于坐标机制,任何Maven项目使用任何一个构件的方式是完全相同的。在此基础上,maven可以在某个位置统一存储所有maven项目共享的构件,这个统一的位置就是仓库。
实际的maven项目只需要声明这些依赖的坐标,在需要的时候,maven会自动根据坐标找到仓库中的构件,并使用他们。
仓库的布局
布局就是maven的超级POM中的<layout>
这段,默认布局(default)如下:
根据坐标可以定义其在仓库中的唯一存储路径。该路径与坐标的大致关系为groupId/artifactId/version/artifactId-version.packaging
。
maven仓库是基于简单文件系统存储的,因此,当遇到了一些与仓库相关的问题时,可以很方便地查找相关文件,方便定位问题。
仓库的分类
仓库只分为两类:本地仓库和远程仓库。当maven根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,maven就会去远程仓库查找,发现需要的构件之后,下载到本地仓库在使用。如果本地和远程都没有,就会报错。
maven仓库的分类如下图:
本地仓库
本地仓库在~/.m2/repository/
。如果想要自定义本地仓库目录地址,可以编辑文件~/.m2/settings.xml
,设置localRepository
元素的值为想要的仓库地址。(这个配置xml默认不存在,需要从M2_HOME中复制过去一个)
另外,maven的install插件也是将项目构建输出文件安装到本地仓库。
远程仓库
对于maven来说,每个用户只有一个本地仓库,但可以配置访问很多远程仓库。
中央仓库
由于最原始的本地仓库是空的,maven必须知道至少一个可用的远程仓库,才能子啊执行maven命令的时候下载到需要的构件。中央仓库就是这样一个默认的远程仓库,maven的安装自带了中央仓库的配置。在$M2_HOME/lib/maven-model-builder-3.6.1jar
中的pom-4.0.0.xml
文件下看到:
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
这段配置文件是所有maven项目都会继承的超级POM。
私服
私服代理广域网上的远程仓库,供局域网内的maven用户使用。
当maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为maven的下载请求提供服务。此外,一些无法从外部仓库下载到的构件也能从本地上传到私服上供大家使用
私服的优点:
- 节省自己的外网带宽。
- 加速Maven构建
- 部署第三方构件。(二方库)
- 提高稳定性,增强控制。
- 降低中央仓库的负荷。
常见的私服软件包括: JFrog Artifactory和 Nexus
https://www.jfrog.com/confluence/display/JFROG/JFrog+Artifactory
远程仓库的配置
-
远程仓库的配置:可以通过
<repositoriese>
标签直接在pom中配置。 -
远程仓库的认证
配置认证信息和配置仓库信息不同,仓库信息可以直接配置在pom文件中,但是认证信息必须配置在settings.xml文件中。
可以通过私钥配置,也可以同账号密码配置。
<!-- servers | This is a list of authentication profiles, keyed by the server-id used within the system. | Authentication profiles can be used whenever maven must make a connection to a remote server. |--> <servers> <!-- server | Specifies the authentication information to use when connecting to a particular server, identified by | a unique name within the system (referred to by the 'id' attribute below). | | NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are | used together. | <server> <id>deploymentRepo</id> <username>repouser</username> <password>repopwd</password> </server> --> <!-- Another sample, using keys to authenticate. <server> <id>siteServer</id> <privateKey>/path/to/private/key</privateKey> <passphrase>optional; leave empty if not used.</passphrase> </server> --> </servers>
-
部署至远程仓库
Maven除了能对项目进行编译、测试、打包之外,还可以将项目生成的构建部署到仓库中。首先,需要编辑项目的pom.xml文件。配置
distributionManagement
元素。<distributionManagement> <repository> <name>xxx </name> <id>xxx-release</id> <url>private serve release url</url> </repository> <snapshotRepository> <name>xxx </name> <id>xxx-snapshot</id> <url>private serve snapshot url</url> </snapshotRepository> </distributionManagement>
往远程仓库部署构建的时候,需要认证。配置认证的在上面讲了,即在settings.xml中创建一个server元素,其id与仓库的匹配,并配置正确的认证信息。
配置正确后,在命令行运行
mvn clean deploy
,就会项目构建输出的构件部署到配置的对应的远程仓库,如果当前的版本是快照版本,则部署到快车版本仓库地址,否则就是release地址。
快照版本
-
是什么?
- snapshot:2.1-SNAPSHOT、2.1-20091215.221414-14、
- release:1.0.0、1.3-alpha-4、2.0
-
Maven为什么要区分release和snapshot?
-
maven的快照版本是为了解决合作开发时候,模板B依赖模块A部分新功能情况下,需要对模块A的新功能进行临时打包 。
-
如果对模块A的版本设定为
2.1-SNAPSHOT
,然后发布到私服中,在发布过程中,Maven会自动为构建打上时间戳。比如2.1-20091215.221414-14
表示2009年12月15日22点14分14秒的第14次快照。有了该时间戳,maven就能够随时找到仓库中该构件版本的最新文件。 -
当构建模块B的时候,Maven会自动从仓库中检查模块A的最新构建,当发现有更新时便进行下载。默认Maven是每天检查一次更新(由仓库的updatePolicy控制),也可以使用
mvn clean install -U
强制Maven检查更新。
-
当项目经过完善的测试后需要发布的时候,就应该将快照版本更改为发布版本。例如,讲2.1-SNAPSHOT更改为2.1,表示该版本已经稳定,且只对应了唯一构件。相比之下,2.1-SNAPSHOT往往对应了大量的带有不同时间戳的构件,这也决定了其不稳定性。
-
从仓库解析依赖的机制
当本地仓库没有依赖构件的时候,Maven会自动从远程仓库下载;当依赖版本为快照版本的时候,maven会自动找到最新的快照。则背后的依赖解析机制可以概括如下:
- 当依赖的范围是system的时候,maven直接从本地文件系统解析构件
- 根据依赖坐标计算仓库路径后,尝试直接从本地仓库寻找构件,如果发现相应构件,则解析成功。
- 在本地仓库不存在相应构件的情况下,如果依赖的版本是显式的发布版本构件,如1.2、2.1-beta-1,则遍历所有的远程仓库,发现后,下载并解析使用。
- 如果依赖的版本是RELEASE或者LATEST,则基于更新策略读取所有远程仓库的元数据
groupId/artifactId/maven-metadata.xml
,将其与本地仓库的对应元数据合并后,计算出RELEASE或者LASTEST真实的值,然后基于这个真实的值检查本地和远程库。 - 如果依赖的版本是SNAPSHOT,则基于更新策略读取所有远程仓库的元数据
groupId/artifactId/maven-metadata.xml
,将其与本地仓库的对应元数据合并后,得到最新快照版本的值,然后基于该值检查本地仓库,或者从远程仓库下载。 - 如果最后解得到的构件版本是时间戳格式的快照,则复制其时间戳格式的文件至非时间戳格式,如SNAPSHOT,并使用该非时间戳格式的构件。
【需要看源码】
前面提到的RELEASE和LATEST版本,它们分别对应了仓库中存在的该构件的最新发布版本和最新版本(包含快照),而这两个“最新”是基于groupId/artifactId/maven-metadata.xml
计算出来的。
【这个xml可以在maven仓库看到】
最后,仓库元数据并不是永远正确的,有时候当用户无法解析某些构件,或者解析得到错误构件的时候,就有可能是出现了仓库元数据错误,这时候就需要手工地,或者使用工具对其进行修复。
镜像
如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。
关于镜像,一个更常见的用法是结合私服。由于私服可以代理任何外部的公共仓库,因此,对于内部的maven用户来说,使用一个私服地址就等于使用了所有需要的外部镜像,这可以将配置集中到私服,从而简化Maven本身的配置。
具体的一个镜像配置如下:
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
该例中<mirrorOf>
值为星号,表示该配置是所有Maven仓库的镜像,任何对于远程仓库的请求都会被转至阿里云。如果该镜像仓库需要认证,则配置一个id为internal-repository
的<server>
即可。
为了满足一些复杂的需求,maven还支持更高级的镜像配置:
<mirrorOf>*</mirrorOf>
:匹配所有的远程仓库<mirrorOf>external:*</mirrorOf>
:匹配所有远程仓库,使用localhost的除外,使用file://协议的除外。<mirrorOf>repo1,repo2</mirrorOf>
:匹配仓库repo1和repo2,使用逗号分隔多个远程仓库。<mirrorOf>*,! repo1</mirrorOf>
:匹配所有远程仓库,repo1除外,使用感叹号将仓库从匹配中排除。
仓库搜索服务
-
Sonatype Nexus:http://repository.sonatype.org/
-
Jarvana:http://www.jarvana.com/jarvana
- 提供了基于关键字、类名的所有,构建下载、依赖声明片段等功能也一应俱全。
-
MVNbrowser:http://www.mvnbrowser.com
-
MVNrepository(百度第一个):https://mvnrepository.com/
上述四个仓库搜索服务都代理了主流的Maven公共仓库,比如central,JBoss,Java.net等。区别只有页面风格和额外功能。
补充
JFrog Artifactory 和Nenus
todo