在Maven世界中,任何一个依赖、插件或者项目构建的输出,都可以称为构件。如依赖log4j-1.2.15.jar
是一个构件,插件maven-compiler-plugin-2.0.2.jar
是一个构件。
Maven坐标为各种构件引入了秩序,任何一个构件都必须明确定义自己的坐标,而一组Maven坐标是通过一些元素定义的,它们是 groupId,artifactId,version,packaging,class-sifer。下面是一组坐标定义:
<groupId>com.mycompany.appgroupId>
<artifactId>my-appartifactId>
<packaging>jarpackaging>
<version>0.0.1-SNAPSHOTversion>
在理解什么是仓库前,我们先来想象一下的这样一个场景:
在一台工作站上,可能会有几十个项目,这些项目中的大部分都用到了 log4j
,有一小部分用到了 Spring Framework
,还有另外一小部分用到了 Struts2
。在每个有需要的项目中都放置一份重复的 log4j
或者 struts2
显然不是最好的解决方案,**这样做不仅造成了磁盘空间的浪费,而且也难于统一管理,文件的复制等操作也会降低构建的速度。**而实际情况是,在不使用 Maven 的那些项目中,我们往往就能发现命名为 lib/
的目录,各个项目lib/
目录下的内容存在大量的重复。
那么应该怎么解决这种空间浪费和难于统一管理的问题呢?
得益于 Maven 的 坐标机制,任何 Maven项目使用任何一个构建的方式都是完全相同的,Maven 可以在某个位置统一存储所有的 Maven 项目共享的构建,这个统一的位置就是仓库,项目构建完毕后生成的构建也可以安装或者部署到仓库中,供其它项目使用。
任何一个构件都有其唯一的坐标,根据这个坐标可以定义其在仓库中的唯一存储路径,这便是Maven的仓库布局方式。
如log4j:log4j:1.2.16
这一依赖:
其对应的仓库路径为:log4j/log4j/1.2.16/log4j-1.2.16.jar
该路径与坐标的大致对应关系为:groupId/artifactId/version/artifactId-version.packaging
Maven仓库是基于简单文件系统存储的,如果遇到仓库相关的问题时,我们可以查找相关文件,定位问题。例如,当maven无法获得项目声明的依赖时,可以查看该依赖对应的文件在仓库中是否存在,如果不存在,查看是否有其他版本可用,等等。
对于Maven来说,仓库分为两类:本地仓库 和 远程仓库。
当Maven根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件之后,下载到本地再使用。如果本地仓库和远程仓库都没有需要的构件,Maven就会报错。
Maven仓库的分类
本地仓库是指用户本机中的的仓库,一般在Maven项目中,没有lib/
这样的依赖文件的目录。当Maven项目进行编译和运行的时候,需要的依赖文件必须在本地仓库中存在才可以被Maven项目所使用。
本地仓库默认位置在${user.home}/.m2/repository
目录下。假设我的用户名为Dong
,那么在Windows中仓库地址为C:\Users\Dong\.m2\repository
,而Linux上的本地仓库地址为home/Dong/.m2/repository/。
注意:Liunx中以点(.)开头的文件或目录默认隐藏的,可以使用
ls-a
命令查看。
可以通过编辑Maven的配置文件:settings.xml
,设置localRepository
元素的值为想要的仓库地址。如:
<settings>
<localRepository>D:\Soft\maven\maven_jar\repositorylocalRepository>
settings>
此时,用户的本地仓库就被设置成了D:\Soft\maven\maven_jar\repository
。
通过在项目的pom中配置依赖,dependency下载需要的依赖到本地仓库。
在某个maven项目根目录下执行:mvn clean install
命令就可以把项目以构件形式安装到本地仓库中
别人开发好的一个jar包,但是没有发布到maven中央仓库中,我需要在maven项目中使用,所以,我们可以通过命令将该jar包添加到本地仓库中,这样就可以在项目中声明使用了,声明一个构件当然需要groupId\artifactId、version
。
**需求:**假设把jar:g:\edu.mit.jwi_2.3.3_jdk.jar
安装到本地仓库,并且自定义它的 gourpId=local.edu.stanford; artifactId=edu.mit.jwi_jdk;version=2.3.3;packaging =jar
操作: 在命令行中执行如下命令即可。
mvn install:install-file -Dfile=g:\edu.mit.jwi_2.3.3_jdk.jar -DgroupId=local.edu.stanford -DartifactId=edu.mit.jwi_jdk -Dversion=2.3.3 -Dpackaging=jar
远程仓库相对本地仓库,本地仓库不存在的构件才会从远程仓库下载,并保存在本地仓库中。对maven来说,每个用户只有一个本地仓库,但可以配置访问很多远程仓库。
由于最原始的本地仓库是空的,Maven必须知道至少一个可用的远程仓库,才能在执行maven命令的时候下载需要的构件。中央仓库就是这样一个默认的远程仓库,中央仓库的信息在超级Pom中配置,所有的maven项目都会继承超级POM。 超级POM的位置: $M2_HOME/lib/maven-model-builder-3.0.jar
,然后访问路径org/apache/maven/model/pom-4.0.0.xml
,可以看到配置:
<repositories>
<repository>
<id>centralid>
<name>Central Repositoryname>
<url>https://repo.maven.apache.org/maven2url>
<layout>defaultlayout>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
repositories>
解释:
私服是一种特殊的远程仓库,它是架设在局域网的仓库服务,私服代理广域网上的远程仓库,供局域网使用。
私服的用途
私服的好处:
默认的中央仓库无法满足项目需求,可能需要的构件在另外一个远程仓库,如JBoss Maven仓库,可以POM中配置该仓库。
<repositories>
....
<repository>
<id>jbossid>
<name>JBoss Repositoryname>
<url>https://repository.jboss.com/maven2/url>
<layout>defaultlayout>
<snapshots>
<enabled>falseenabled>
snapshots>
<releases>
<enabled>trueenabled>
releases>
repository>
....
repositories>
在repositories
元素下,可以使用repository
子元素声明一个或者多个远程仓库。在该例中,生命了一个id为jboss,名称为JBoss Repository
的仓库。
注意:
releases
的enabled=true
表示开启JBoss仓库的发布版本下载支持。根据以上配置,maven只从JBoss仓库下载发布版本的构件不会下载快照版本。<releases>
<enabled>trueenabled>
<updataPolicy>dailyupdataPolicy>
<checksumPolicy>warnchecksumPolicy>
releases>
有时候处于安全考虑,需要提供认证信息才能访问一些远程仓库。为了能让maven访问仓库内容,就需要配置认证信息,认证信息的配置不会在pom.xml
配置,而是在settings.xml
中配置,因为pom会被提交到代码仓库中供所有成员访问,而settings.xml
一般只放在本机。
假设我在pom.xml
中配置id=my-proj
的远程仓库,需要认证信息,则在settings.xml
中配置如下:
<settings>
...
<servers>
<server>
<id>my-projid>
<username>repo-userusername>
<password>repo-pwdpassword>
server>
servers>
...
settings>
- 这里的
id=my-proj
一定要和pom.xml
中仓库的id一致,这是它们之间唯一的联系。
settings.xml
的servers
中就是用来配服务器授权信息的,当然不仅可以配置仓库服务器认证信息,还可以配置其它的比如tomcat
服务器授权信息也可以在这里配置。如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。
例如:在国内直接连接中央仓库下载依赖,由于一些特殊原因下载速度非常慢。这时,我们可以使用阿里云提供的镜像http://maven.aliyun.com/nexus/content/groups/public/来替换中央仓库http://repol.maven.org/maven2/。
修改maven的setting.xml文件,内容如下:
<settings>
<mirrors>
<mirror>
<id>alimavenid>
<name>aliyun mavenname>
<url>http://maven.aliyun.com/nexus/content/groups/public/url>
<mirrorOf>centralmirrorOf>
mirror>
mirrors>
settings>
mirrorOf
为central
,表示该配置为中央仓库的镜像,任何对于中央仓库的请求都会转至该镜像,用户也可以使用该方法配置其它仓库的镜像。另外三个参数和配置一般远程仓库一样。*
:匹配所有远程仓库。external:*
:匹配所有远程仓库,使用 localhost
的除外,使用file://
协议的除外。repo1,repo2
:匹配仓库repo1,repo2,多个使用逗号分隔。*,!repo1
:匹配所有远程仓库,repo1除外。需要注意的是:由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven 仍无法访问镜像仓库,因而将无法下载构件。
system
时候,Maven直接从本地文件解析构件。updatepolicy
的原因,可能要求本机能连接到远程仓库(远程仓库可以是私服或者中央仓库,一般只有自己的项目会使用SNAPSHOT
,所以大多数是私服)SNAPSHOT
,并使用该时间戳格式的构件。version
值为RELEASE
时(不建议),Maven会基于updatepolicy策略读取远程仓库的元数据groupId/artifactId/maven-metadata.xml,将其与本地仓库相对应元数据合并后,计算出最新版本的RELEASE值(稳定版),然后基于这个值检查本地和远程仓库,步骤如2和3。