Maven 仓库
Maven 仓库布局
Maven 坐标是构件在 Maven 世界中的逻辑表示方式,而构件和物理表示方式是文件, Maven 通过仓库来统一管理这些文件。根据 Maven 的标示可以定义构件在仓库中的唯一路径,这便是 Maven 的仓库布局方式。Maven 默认的坐标和路径的关系为:groupId/artifactId/version/artifactId-version.packaging。
仓库的分类
-
本地仓库
Maven 项目中是没有诸如 lib 这样用来存放依赖文件的目录,在执行编译或测试时,如果需要使用依赖文件,它总是基于坐标使用本地仓库的依赖文件。默认仓库的目录位于用户目录下 .m2/repository/ 目录,用户也可以通过编辑 Maven 配置文件 settings.xml 来自定义本地仓库的目录地址,如下:
<localRepository>E:\柘城\repository</localRepository>
-
中央仓库
Maven 自带了中央仓库的配置, $M2_HOME\lib\maven-model-builder-3.3.9.jar\org\apache\maven\model\pom-4.0.0.xml中可以看到如下配置,其实这个文件是 Maven 的超级 POM,所有的 Maven 项目都会继承它。
<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 用户使用。它的好处有:节省外网带宽、加速 Maven 构建、部署第三方构件、提高稳定性,增强控制、降低中央仓库的负荷。
远程仓库的使用
-
远程仓库的配置
使用默认的中央仓库有的时候可能下载构件比较慢,这时我们就可以再配置一个远程仓库,可以在 POM 中配置该仓库。POM 中配置如下:
<project> <repositorys> <repository> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <layout>default</layout><!----> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> <updatePolicy>daily</updatePolicy> <checksumPolicy>warn</checksumPolicy> </snapshots> </repository> ... </repositorys> </project>
注意仓库声明的id必须是唯一的, Maven 自带的中央仓库的 id 为 central, 如果其它仓库声明也使用该 id,就会覆盖中央仓库。layout 元素值 default 表示仓库布局是 Maven 2 及 Maven3 默认布局,releases 的 enabled 为true 表示开启发布版本的下载支持,而 snapshots 的 enabled 为 true 表示开启快照版本的下载支持。对于releases 和 snapshots 来说还有另外两个元素 updatePolicy 和 checksumPolicy, updatePolicy用来配置 Maven 从远程仓库检查更新频率,默认是 daily,表示每天检查一次,还有 never – 从不检查、always – 每次构建检查更新、interval:X – 第隔X分钟检查一次更新(X为任意整数)。元素 checksumPolicy 用来配置 Maven 检查检验和文件的策略,默认是 warn – 警告,还有 fail – 构建失败、ignore – 忽略。
-
远程仓库的认证
出于安全方面的考虑,有时候我们需要提供认证信息才能访问一些远程仓库。注意认证信息必须配置在 settings.xml 文件中,因为 POM 往往是被提交到代码仓库供所有成员访问的,而 settings.xml 一般中放在本机,这样更为安全。server 元素的 id 必须和需要认证的 repository 元素的 id 完全一致才行。认证配置如下:
<settings> ... <servers> <server> <id>alimaven</id> <username>username</username> <password>password</password> </server> ... </servers> ... </settings>
-
部署至远程仓库
往往在工作中都需要我们把项目部署到远程仓库上(公司私服)供团队成员使用,此时只需要在项目的 POM 文件中进行相应配置后运行 mvn clean deploy 命令,Maven 就会将项目部署到对应的远程仓库。POM 配置如下:
<project> ... <distributionManagement> <repository> <id>proj-releases</id> <name>Proj Release Repository</name> <url>http://192.168.0.124/content/repositories/proj-releases</url> </repository> <snapshotRepository> <id>proj-snapshots</id> <name>Proj Snapshot Repository</name> <url>http://192.168.0.124/content/repositories/proj-snapshots</url> </snapshotRepository> </distributionManagement> ... </project>
其中 repository 元素表示发布版本构件的仓库,snapshotRepository 表示快照版本的仓库。向远程仓库部署构件往往是需要认证的,请参考 2.远程仓库的认证。
-
快照版本
在 Maven 的世界中,任何一个项目或构件都必须有自己的版本。如 1.1、1.1-alpha-1、1.1-SHAPSHOT或者1.1-20170528.050501-1。其中1.1、1.1-alpha-1是稳定发布版本,1.1-SHAPSHOT或者1.1-20170528.050501-1是不稳定的快照版本。它两的不同在于:一个稳定版本只会对应一个唯一的构件,但一个快照版本会对应大量带有不同时间戳的构件。Maven 在把快照版本的构件发布至私服时会自动为构件打上时间戳,如 1.1-20170528.050501-1 就表示2017年5月28日5点5分1秒的第1次快照。当项目引入快照版本的构件时,即使本地仓库中已存在该构件,Maven 还是每天都到远程仓库去检查一次更新(由仓库配置的 updatePolicy 控制,默认为 daily,每天检查一次),用户也可以使用命令行 -U 参数强制让 Maven 检查更新,如:mnv clean install -U。如果项目引入的是一个发布版本的构件,如果本地仓库已存在,那 Maven 就不会再到远程仓库进行更新了,除非本地仓库的构件被清除了。一般在项目的开发过程中都使用快照版本,当项目测试通过后需要发布的时候就应该将快照版本更改为发布版本。例如将 1.1-SHAPSHOT 更改为 1.1,表示该版本已经稳定,且只对应了唯一的构件。
-
从仓库解析依赖的机制
当本地仓库没有依赖构件的时候,Maven 会自动从远程仓库下载,当依赖版本为快照版本的时候,Maven 会自动找到最新的快照。具体的依赖解析机制概括如下:
-
当依赖范围是 system 时,Maven 直接从本地文件系统解析构件。
-
根据依赖坐标计算仓库路径后,尝试直接从本地仓库寻找构件,如果发现相应构件,则解析完成。
-
在本地仓库不存在相应构件的情况下,如果依赖的版本是显示的发布版本构件,如1.1、1.1-beta-1 等,则遍历所有的远程仓库,发现后下载,解析完成。
-
如果依赖的版本是 RELEASE(最新发布版本) 或者 LATEST(最新版本,包括快照),则基于仓库更新策略读取所有远程仓库的元数据 groupId/artifaceId/maven-metadata.xml,将其与本地仓库对应元数据合并后,计算出 RELEASE 或者 LATEST 真实的值,然后基于这个真实的值检查本地和远程仓库,如前两个步骤。
-
如果依赖的版本是 SNAPSHOT,则基于仓库的更新策略读取所有远程仓库的元数据 groupId/artifactId/version/maven-metadata.xml,将其与本地仓库的对应元数据合并后,得到最新的快照版本号,然后基于该版本号检查本地仓库,或者从远程仓库下载。
-
如果最后解析到的构件版本是时间戳格式的快照,如 1.1-20170528.050501-1,则复制其时间戳格式的文件至非时间戳格式,如 SNAPSHOT,并使用该非时间戳格式的构件。如 SNAPSHOT 版本的构件在远程仓库的文件格式为 maven_test-0.0.1-20170528.050501-1.jar,但 Maven 下载该构件到本地仓库后会自动修改为 maven_test-0.0.1-SNAPSHOT.jar。
在依赖中使用 RELEASE 和 LATEST 是不推荐的做法,因为 Maven 随时都可能解析到不同的构件,当这种变化造成构建失败的时候,发现问题会变得比较困难。为此 Maven 3 不再支持在插件配置中使用 LATEST 和 RELEASE。但如果不设置插件版本,其效果还是和 RELEASE 一样,Maven 只会解析最新的发布版本构件。注:当 Maven 无法解析某些构件,或者解析得到错误构件的时候,可能是出现了仓库的元数据错误,这时就需要手工的或者使用工具(如 Nexus)对其进行修复。
-
镜像
如果仓库 X 可以提供仓库 Y 存储的所有内容,那么就可以认为 X 是 Y 的一个镜像,换句话说,任何一个可以从仓库 Y 获得的构件,都能从它的镜像 X 中获得。镜像的一个常见用法是结合私服,由于私服可以代理任何外部的公共仓库,所以使用一个私服地址就等于使用了所有需要的外部仓库,这样可以将配置集中到私服 ,从而简化 Maven 本身的配置,在这种情况下,任何需要的构件都可以从私服获得,即私服就是所有仓库的镜像。这时我们可以在 settings.xml 文件中配置一个镜像。镜像配置如下:
<settings> ... <mirrors> <mirror> <id>mirrorId</id> <mirrorOf>repositoryId</mirrorOf> <name>Name</name> <url>http://my.repository.com/repo/path</url> </mirror> </mirrors> ... </settings>
id、name、url 这三个元素与一般仓库配置无异,表示仓库的唯一标识符、名称以及地址,类似的,如果该镜像需要认证,也可以基于该 id 配置仓库认证。mirrorOf 元素表示被镜像仓库的 id,如 central,表示对中央仓库的镜像,任何对于中央仓库的请求都会转至该镜像。为了满足一些复杂的需求,Maven 还支持理高级的镜像配置:
- *:匹配所有远程仓库。
- external:*:匹配所有远程仓库,使用 localhost 的除外,使用 file://协议的除外。也就是说,匹配所有不是本机上的远程仓库。
- repo1,repo2:匹配仓库 repo1 和 repo2,使用逗号分隔多个远程仓库。
- *,!repo1:匹配所有远程仓库,repo1 除外,使用感叹号将仓库从匹配中排除。
需要注意的是,由于镜像仓库完全屏蔽了被镜像的仓库,当镜像仓库不稳定或者停止服务的时候,Maven 仍将无法访问被镜像的仓库,因而将无法下载构件。