Maven坐标和依赖是任何一个构件在Maven世界中的逻辑表示方式;而构件的物理表示方式是文件,Maven通过仓库来统一管理这些文件。
Maven仓库
在Maven的世界中,任何一个依赖、插件或者项目构建的输出,都可以称为一个构件。如项目依赖log4j-1.2.15.jar是一个构件,插件maven-compiler-plugin-2.0.3.jar是一个构件,我们自己的Maven项目构建完成后的输出.jar/war文件也是一个构件。任何一个构件都有一组坐标唯一标识。在我们项目开发中,往往可能会涉及到十几个甚至几十个Maven项目,可能大部分项目都需要log4j来打印日志,那么是否我们需要在每一个Maven项目中buildpath一份log4j的java类库呢?答案显然不是,本着重用性的原则,我们最好把这个java类库放在一个地方,所有要用到log4j的Maven项目都共用一份log4j java类库,那么这个地方就是Maven仓库。为了实现重用,项目构架完毕后生成的构件也可以安装或者部署到Maven仓库中供其他Maven项目使用。
仓库布局
任何一个构件都有其唯一坐标,根据这个坐标可以定义其在仓库中的唯一存储路径,这便是Maven的仓库布局方式。例如log4j:log4j:1.2.15这一依赖,那么其对应的仓库路径为log4j/log4j/1.2.15/log4j-1.2.15.jar,改路径与pom对应的坐标关系为groupId/artifactId/version/artifactId-version.packaging。
仓库的分类
对于Maven来说,仓库只分为两类:本地仓库和远程仓库。当Maven根据坐标寻找构件的时候,它会首先查看本地仓库,如果本地仓库存在构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件之后,下载到本地仓库再使用。如果本地仓库和远程仓库都没有需要的构件,Maven就会报错。
中央仓库是Maven核心自带的远程仓库,它包含了绝大部分开源的构件。在默认配置下,当本地没有找到Maven需要的构件的时候,它就会自动尝试从中央仓库下载。
私服是另一种特殊的远程仓库,稍有规模的企业都会在局域网内搭建这样一个私服,用其代理所有外部的远程仓库,不仅速度更快,而且内部项目还能部署到私服上供其他项目使用。
其他公开的远程仓库,常见有Java.net.Maven库和JBoss Mavn库。
本地仓库
一般来说,在Maven项目目录下没有诸如lib/这样用来存放依赖文件的目录。当Maven执行编译或测试时,如果需要使用依赖文件,它总是基于坐标使用本地仓库的依赖文件。
默认情况下,每个Maven用户在自己的用户目录下都有一个路径名为.m2/repository/的仓库目录,一般在C盘的用户目录下。实际上.m/目录下还有一个setting.xml文件(一般使用IDE Maven插件的朋友会发现,setting.xml文件已经自动复制过来了,如果没有,我们可以手动从Maven的安装目录下的conf文件夹下复制setting.xml到.m/目录下)。Repository目录里放置的就是本地需要的所有构件。由于系统盘磁盘大小有限,而一个.m2文件随便可以达到几个G甚至十几个G,所以我们有强烈的愿望,希望能把本地仓库搬家,这个倒也不难,只需要在setting.xml文件修改一下如下配置即可:
<localRepository>e:/MavenRepository</localRepository>
这个即为本地仓库的地址。
Maven安装好后,如果不执行任何Maven命令,本地仓库目录是不存在的。当用户输入第一条Maven命令之后,Maven才会创建本地仓库,然后根据配置和需要,从远程仓库下载构件至本地仓库。
中央仓库
由于最原始的本地仓库是空的,Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令的时候下载到需要的构件。中央仓库就是这样一个默认的远程仓库,Maven安装文件自带了中央仓库的配置。我们可以打开Maven的安装目录,在lib/下找到maven-model-builder.jar(每个人版本可能不一样),然后利用反编译工具,可以找到org/apache/maven/model/pom-4.0.0.xml文件,可以看到如下配置:
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>http://repo.maven.apache.org/maven2</url>
<layout>default</layout>//默认仓库布局方式
<snapshots>//快照版本
<enabled>false</enabled>//不从中央仓库下载快照版本的构件
</snapshots>
</repository>
</repositories>
私服
私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,当Maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部远程仓库下载,缓存在私服上之后,再为Maven的下载提供服务。
私服强大之处在于:
1、能节省自己的外网宽带。
2、加速Maven构建。不停地连接外部仓库是十分耗时的,但是Maven的一些内部机制(如快照更新检查)要求Maven在执行构建的时候不停地检查远程仓库数据。因此,当项目配置了很多外部远程仓库的时候,构建的速度会被大大降低。使用私服可以很好地解决这个问题。
3、部署第三方构建。
当某个构件无法从任何一个外部远程仓库获得,怎么办?很典型的例子是,JDBC驱动由于版权因素不能发布到公共仓库中。建立私服后,便可以将这些构件部署到这个内部仓库中,供内部的Maven项目使用。
4、安全性。从两点上得到保障,一是及时暂时没有Internet连接,由于私服中已经缓存了大量构件,Maven仍能正常运行;二是有些私服还提供权限管理、仓库分区等服务;
5、降低中央仓库的负荷,如果没有私服,每个人使用Maven都从中央仓库下载,中央仓库承受的压力,下载的速度可想而知。
远程仓库的配置
很多情况下,默认中央仓库无法满足项目的需求,可能项目需要的构件存在另外一个远程仓库中,如JBOSS Maven仓库。这时,我们可以在POM如下配置仓库:
<project>
...
<repositories>
<repository>
<id>jboss</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.com/maven2/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<layout>default</layout>
<repository>
</repositories>
</project>
在repositories元素下,可以使用repository子元素 一个或者多个远程仓库。任何一个仓库声明的id必须是唯一的,该配置中的url指向了仓库的地址,一般采用http协议,releases元素的enabled的值为true,snapshots元素的enabled的值为false,则说明,只会下载远程仓库发布版本的构件而不会下载快照版本的构件。对于releases和snapshots,它们还包含了另外两个元素updatePolicy和checkSumPolicy。
<releases>
<updatePolicy>daily</ updatePolicy>
<enabled>true</enabled>
<checkSumPolicy>ignore</checkSumPolicy>
</releases>
updatePolicy为从Jboss仓库检查的频率,值可以为daily(每天)、never(从不)、always(每次构建都检查)、Interval(每隔多少分钟检查一次)。
checkSumPolicy用来配置Maven检查检验和文件的策略,当构件被部署到Maven仓库时,会同时部署对应的检验和文件。在下载构件的时候,Maven会验证检验和文件。如果验证检验失败,当checkSumPolicy为warn时,Maven会在执行构件时输出警告信息,其他可用的值有:fail当验证检验失败,就让Maven构建失败;ignore完全忽略校验和失误。
远程仓库的验证
大部分仓库都无需认证就可以访问,但有时处于安全方面的考虑,我们需要提供认证信息才能访问远程仓库。为了防止非法的仓库访问,管理员往往会提供一组用户名和密码,这时,为了能访问仓库,就需要在setting.xml文件中配置:
<settings>
...
<servers>
<server>
<id>
my-proj
</id>
<username>
repo-user
</username>
<password>
repo-password
</password>
</server>
</servers>
</settings>
etting文件中的server的id必须与pom文件的需要认证的repository元素的id一致,正是此id将认证信息和仓库配置联系在了一起。
将构件部署至远程仓库
编辑项目pom.xml文件
<project>
...
<distributionManagement>
<repository>
<id>proj-releases</id>
<name>proj releases repository</name>
<url>http://192.168.2.11:1521/proj-releases/</url>
</repository>
<snapshotRepository>
<id>proj-snapshots</id>
<name>proj snapshots repository</name>
<url>http://192.168.2.11:1521/projsnapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
往远程仓库部署构件的时候,往往需要认证。简而言之,就是需要在setting文件中配置server元素,其id与仓库的id匹配,并配置正确的认证信息。
镜像
如果仓库x可以提供仓库y存储的所有内容,那我们可以说x是y的镜像,典型的事例是,很多国外的服务在中国都有中国的镜像,这样的目的是能够提供更快的服务。
<settings>
...
<mirrors>
<mirror>
<id>maven.net.cn</id>
<name>one of the central mirror in China</name>
<url>http://maven.net.cn/content/groups/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>
以上就是配置的就是中央仓库在中国的镜像。
镜像更为常见的是结合私服的使用,由于私服可以代理任何外部的公共仓库,因此,对于组织内部的Maven用户来说,使用一个私服地址,就相当于使用了所有需要的外部仓库,这可以将配置集中到私服,从而简化Maven本身的配置,在这种情况下,任何需要的构件都可以从私服获得,私服就是所有仓库的镜像,这时可以如此配置:
<settings>
...
<mirrors>
<mirror>
<id>internal repository</id>
<name>internal repository manager</name>
<url>http://192.168.2.11:1521/maven2/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
</settings>
mirrorOf元素的值为*代表该配置是所有仓库的镜像,任何对于远程仓库的请求都会被转至http://192.168.2.11:1521/maven2/。
Maven还支持其他高级的镜像配置:
<mirrorOf>*</mirrorOf>
<mirrorOf>external:*</mirrorOf>匹配所有不在本机上的远程仓库
<mirrorOf> repo1,repo2</mirrorOf>匹配仓库repo1,repo2
<mirrorOf> *,!repo2</mirrorOf>匹配所有仓库,repo2除外
需要注意的是,由于镜像仓库完全屏蔽掉被镜像仓库,当镜像仓库不稳定或者停止服务的时候, Maven仍将无法访问被镜像仓库,因而无法下载构件。