目前在看nexus
私服章节的知识时需要用到仓库与镜像的知识,正好通过简书把仓库和镜像章节的笔记整理一下
仓库
maven
可以在某个位置统一存储所有maven
项目共享的构件,这个统一的位置就称之为仓库
任何一个构件都有一个唯一的坐标,通过这个唯一的坐标就可以定义当前构件在仓库中的唯一路径,该路径与maven
的坐标大致关系为: groupId/artifactId/version/artifact-version.packaging
jar
包路径的生成
maven
中任何构件的路径都不是凭空得来的, 而是通过坐标元素计算的,并且可以确定的是每一个构件的路径都是唯一的(假定以构件坐标groupId:artifactId:version:classifier:packaging=org.testng:tesning:5.8:jdk15:jar
为例):
- 基于构建的
groupId
准备路径,将groupId
中的.
分隔符转变为文件分隔符/
,如org/testnng
- 基于构建的
artifactId
准备路径,在前面的路径基础上加上文件分隔符/
再拼接上artifactId
,如org/testng/testng
- 使用版本信息,在前面路径基础上加上文件分隔符和版本,如
org/testng/testng/5.8
- 依次加上文件分隔符、
artifactId
、构建分隔符-
、版本信息,如org/testng/testng/5.8/testng-5.8
- 如果构件存在
classifier
,就加上构建分隔符-
与classifier
,如org/testng/testng/5.8/testng-5.8-jdk15
- 检查构件的
extension
,若extension
存在,则加上句点分隔符.
和extension
(这里的extension
是由packaging
决定的),如org/testng/testng/5.8/testng-5.8-jdk15.jar
在了解了构件路径之后,当我们遇到maven无法找到项目声明的依赖时,可以查看对应构件在仓库中的位置中是否存在,如果不存在则检查是否有其他版本可用,具体可以参考mvnrepository仓库中的依赖说明
仓库分类
从大的范围来说,maven
其实只有两种类型的仓库:本地仓库和远程仓库,在远程仓库中又分为三大类:中央仓库、私服、第三方仓库,他们之间的关系如下:
本地仓库
在maven
项目中是没有/lib
这种用于存放依赖文件的目录的,当maven
需要编译、测试时,它总是基于坐标使用本地仓库中的依赖文件
本地仓库默认在【用户目录/.m2/repository
】下,windows
系统环境下目录在:C:\Users\User\.m2\repository
下,而linux
系统环境则是在/home/User/.m2/repository
,需要注意的是linux
中以.开头的文件都是隐藏文件,可以通过ls -al
命令来查看所有文件
修改maven配置属性的几点建议
在某些情况下,我们可能会更新maven配置文件里面的属性,在不同场景中发挥特定的效果
这时我们可以有两种方式来更新maven配置文件:
- 直接修改maven安装根目录
/conf/settings.xml
配置文件 - 将安装根目录
/conf/settings.xml
拷贝一份到.m2/settings.xml
中,通过修改.m2/settings.xml
中的配置来达到项目要求的效果(推荐这么做)
原因有二:
- 全局配置会影响到其他用户
- maven升级时会覆盖全局配置文件,导致用户的配置失效需要重新配置,而用户目录下的settings.xml则不受限制
不同的项目需要相互引用怎么办呢?
别着急,且听我娓娓道来,maven
已经考虑到这一切,我们只需要通过一条简单命令将被引用的项目打包到本地仓库,这样当前项目才会被其他项目发现并引用,打包项目到仓库命令可以通过执行 mvn clean install
轻松搞定,这样其他项目根据配置的项目坐标到本地仓库去查找指定项目依赖时就会发现当前依赖的项目已经被安装,(maven
执行这条命令时涉及到了又一大核心maven生命周期,这在后续会专门介绍,这里的重点是仓库,这里就不细讲了)
远程仓库
远程仓库是maven下载依赖构件的源,当maven安装之后,在没有执行maven命令之前本地仓库目录是没有被创建的,当执行maven的第一条命令之后,本地仓库会被建立,同时访问远程仓库下载依赖的构件
maven默认的本地仓库路径可以在配置文件settings.xml中自定义,具体配置如下:
<localRepository>G:\workspace\repository</localRepository>
可以通俗的打个比方,本地仓库就好比您的书房,而远程仓库就好比在线或者实体书店,你需要看书时先会在书房中找,如果没有就去网上或者实体书店买并纳入自己的书房,之后就可以从书房中获取到这本书了
下面提供几个实用的仓库,如果配置了私服,可以在私服上代理这些常用仓库
- aliyun仓库
http://maven.aliyun.com/nexus/content/groups/public/
- forge仓库
https://repository.sonatype.org/content/groups/forge/
中央仓库
中央仓库是maven
默认的一个可被访问的远程仓库,配置的具体位置可以查看${M2_HOME}/lib/maven-model-builder-3.3.9.jar
中的org/apache/maven/model/pom-4.0.0.xml
(超级pom
)
下面是截取的超级pom中配置的仓库信息
<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>
私服
私服是一种特殊的远程仓库,它是架设在局域网内部的一种仓库服务,代理广域网上的远程仓库
用户请求下载某一jar
包时,先从私服中找,如果私服中不存在,则遍历远程仓库并下载指定的构件到私服中,并提供给本地仓库下载,最后供用户项目使用
使用私服的好处:
- 减少网络带宽,所有请求都访问私服,而私服则只会访问一次远程仓库,也就是只走一次外网环境
-
加速
maven
的构建速度,不停的请求远程仓库是十分耗时的操作,但maven
的一些内部机制(如快照更新检查,它是什么鬼,后面做解释),所以maven
在构建的时候会不停的检查远程仓库数据 - 部署第三方构建,私服允许将组织内部私有构件部署上去,只有组织内部的人员有权限访问此构件,对于外部用户是透明的
- 降低中央仓库的负荷,所有对中央仓库的请求都集中到了私服上,而当构件不存在时,私服也只是请求一次中央仓库下载对应的构件
-
提高稳定性,增强控制,
maven
的构件高度依赖于仓库,如果没有网络时,maven
构件会失败,但是如果在内网架设私服,那么对外网的访问则由私服代理了,确保maven
在无网络环境下也可以正常工作
配置远程仓库
在项目中,除了由maven
所提供的中央仓库之外,我们还可以配置其他更易于访问的远程仓库,需要修改项目根目录下的pom.xml
文件
<repositories>
<repository>
<id>jboss</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.com/maven2/ </url>
<layout>default</layout>
<release>
<enabled>true</enabled>
</release>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
上面配置了一个jboss
的远程仓库,一般情况下,仓库的url
协议都是基于http
协议的,所以您可以直接在浏览器中访问当前url
,看是否可以访问
需要注意的是,在配置远程仓库时,所有仓库的id是唯一的,尤其需要注意的是,
maven
中央仓库的id
为central
,如果其他仓库使用了此id
则中央仓库就被覆盖了,如此用户也就访问不到中央仓库了下面对releases,snapshots下面的参数做一个介绍
<snapshot>
<enabled></enabled>
<updatePolicy></updatePolicy>
<checkSumPolicy></checkSumPolicy>
</snapshot>
enabled表示从该仓库下载快照版本的构件是否允许
updatePolicy有下面几种取值
daily 每天更新一次仓库数据 (默认) never: 从不更新仓库数据 period: 隔一定的周期更新一次仓库数据 always: 每一次构建都更新仓库数据
checkSumPolicy用于检查从远程仓库下载下来的jar是否正确,如果错误又要如何处理,下面给出了几种情况
ignore:完全忽略构件的校验 warn: 当构件校验和验证失败时给出提示(默认) fail: 当构件校验失败时就让构建失败
远程仓库的认证server
大部分的远程仓库都无需认证就可直接访问,有时候出于安全考虑,我们需要提供认证信息才能访问远程仓库,这时管理员可以为仓库设置用户名密码,此时访问该远程仓库就需要用户提供正确的认证信息,可以在settings.xml
中针对某一个仓库配置认证信息
认证信息与仓库信息不同,需要配置在本机的maven
配置文件settings.xml
中,这是考虑到认证信息的安全性
<settings>
<server>
<id>repositoryid</id>
<username>repo-user</username>
<password>repo-pass</password>
</server>
</settings>
这里需要注意的是server
配置的id要与pom
中配置的需要认证的repository
的id
一致
部署至远程仓库
要想把项目提供给其他模块使用,我们需要把自己的项目模块部署到仓库中供其他模块下载引用,我们需要配置distributeManagement
部署信息
<project>
<distributeManagement>
<repository>
<id>remote-repository-id</id>
<name>remote-repository-name</name>
<url>proj-release</url>
</repository>
<snapshotRepository>
<id>remote-repository-id</id>
<name>remote-repository-name</name>
<url>proj-snapshot</url>
</snapshotRepository>
</distributeManagement>
</project>
repository
表示发布版本的仓库
snapshotRepository
表示快照版本的仓库
当部署信息配置好之后就可以使用命令
mvn clean deploy
将项目打包安装到本地仓库并部署到远程仓库中
快照版本机制snapshot
快照版本要解决的问题是控制未发布版本的部署更新操作,假设A,B
模块都处于未发布版本,现在B
需要依赖A
,如果不考虑快照版本的情况下,B
可以进行下面几种方案来引用A
:
-
B
自己获取A
项目源码进行构建,这可以确保B
获取到A
最新的代码,但B
不得不去构建模块A
,如果A
在构建过程中出现问题,B
可能是抓狂的 -
A
重复部署模块特定版本,比如B
引用A
的2.1版本,那么就基于A
的2.1版本重复部署,虽然A
能确保2.1版本代码是最新的,但是对于B
来说确实未知的,因为相同的版本意味着同样的构件,除非B
先清除本地仓库中的A2.1
,这种需要B
手工干预的方式也是不可取的 -
AB
不停的更新版本,这要求AB
需要不停的更换版本,导致对版本的滥用
maven
的快照版本机制就是为了解决上面的问题,需要将A
的版本设置为2.1-SNAPSHOT
,在发布构成中,maven
会自动为A
打上时间戳,当构件B
时,maven
会自动从仓库中检查模块A
的2.1-SNAPSHOT
的最新版本,当然这项特性与仓库配置的updatePolicy
有关,仓库配置如下:
<repository>
<id></id>
<name></name>
<url></url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</releases>
</repository>
仓库解析依赖的过程
当本地仓库没有依赖的时候,maven
会自动从远程仓库下载,当依赖版本为快照版本的时候,maven
会自动找到最新的快照。那么它是如何找的,具体的依赖机制如下:
- 当依赖范围(
scope
)为system
的时候,maven
会直接从指定的systemPath
系统路径查找指定的依赖 - 根据坐标计算依赖在本地仓库中的位置,如果在指定的位置发现了构件则解析成功
- 在本地仓库不存在依赖的情况下,如果依赖的版本是显示的发布版本如
1.2,1.2-beta-1
,则遍历所有远程仓库,发现后下载到本地仓库 - 如果依赖的版本是
RELEASE
或者LASTEST
,则基于更新策略读取所有远程仓库中的元数据/groupId/artifactId/metadata.xml
,将其与本地仓库的元数据结合后计算出真实的RELEASE
或者LATEST
版本,再基于该版本查找仓库中的依赖,重复2,3 - 当发现依赖的版本是
SNAPSHOT
,则基于更新策略读取所有远程仓库中的元数据roupId/artifactId/version/metadata.xml
,将其与本地仓库的元数据结合后计算出真实的快照版本并重复2,3 - 如果解析到的版本是时间戳格式的快照,如
2.1-20091214.221414-13
,则替换为2.1-SNAPSHOT
这种非时间戳格式的形式
以上4.5.6,在maven3
之后无效,maven3
默认只允许解析最新的发布版本的构件
当然还与仓库配置的<snapshots><enabled>, <releases><enabled>
以及其中的updatePolicy
有关,如果enabled
为false
,则就不存在下载指定类型的依赖这一说了,当命令设置-U
参数如mvn clean install-U
这时会忽略updatePolicy
的设置
不要在发布的构件版本中声明release
或者latest
,这是不推荐的做法,因为基于更新策略maven
会去检查仓库中最新的版本,这可能会因为代码接口的变动而导致项目构件失败
镜像mirror
如果仓库A
能提供仓库B
存储的所有内容,那么就可以认为A
是B
的一个镜像,通俗的说,能从B
中获取的构件那么一定也可以从A
中获取
由于地理位置的原因,通常我们需要设置合理的镜像来代替中央仓库,比如可以设置aliyun
镜像
<settings>
...
<mirrors>
<mirror>
<id>aliyunmaven</id>
<name>Aliyun Maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<mirrorOf>central</mirror>
</mirror>
</mirrors>
</settings>
上面通过配置aliyun
镜像作为中央仓库的镜像,当访问中央仓库时,请求会被代理到镜像服务器上
关于镜像的一个更为常见的用法是结合私服,私服可以代理任何远程仓库,对于组织内部的人来说,使用一个私服就等于使用了所有需要的外部仓库,这时只需要在私服上进行配置,而项目中只需要简单的配置使用私服即可,这时私服就是所有远程仓库的镜像
镜像特殊语法
<mirrorOf>*</mirrorOf>
:匹配所有远程仓库
<mirrorOf>external:*</mirrorOf>
:匹配所有远程仓库,但是排除对本地仓库和系统依赖的访问
<mirrorOf>repo1,repo2</mirrorOf>
:匹配多个仓库,用逗号隔开
<mirrorOf>*,!repo1</mirrorOf>
:匹配所有仓库但排除repo1
仓库
需要注意的是:镜像完全屏蔽了对指定仓库的访问,如果镜像仓库不稳定那么将会导致maven
构建失败!这一点尤为重要
仓库搜索服务
我们需要在项目中引用各种各样的依赖,那么这些依赖的坐标具体是什么,我们可以从下面提供的两种搜索服务中获取到
- Sonatype Nexus
https://repository.sonatype.org/
- MVNrepository
https://mvnrepository.com/
(本人最常用)
好了,篇幅有点长,关于仓库和镜像的知识点还是挺多的,需要慢慢巩固学习