maven3实战之仓库

maven仓库介绍

1.何为Maven仓库
maven可以在某个位置统一存储所有maven项目共享的构件,这个统一的位置就是仓库。实际的Maven项目将不会各自存储其依赖文件,它们只需要声明这些依赖的坐标,在需要的时候(例如,编译项目的时候需要将依赖加入到classpath中),maven会自动根据坐标找到仓库中的构件,并使用它们。为了实现重用,项目构建完毕后生成的构件也可以安装或者部署到仓库中,供其他项目使用。

2.仓库的布局
任何一个构件都有其唯一的坐标,根据这个坐标可以定义其在仓库中的唯一存储路径,这便是Maven的仓库布局方式。例如,log4j:log4j:1.2.15这个依赖,其对应的仓库路径为log4j/jog4j/1.2.15/log4j-1.2.15.jar,该路径与坐标的大致对应关系为groupId/artifactId/version/artifactId-version.packaging

maven仓库分类

对于maven来说,仓库只分为两类:本地仓库和远程仓库maven根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,maven就会去远程仓库查找,发现需要的构件之后,下载到本地仓库再使用。如果本地仓库和远程仓库都没有需要的构件,maven就会报错
在这个最基本分类的基础上,还有必要介绍一些特殊的远程仓库。中央仓库是maven核心自带的远程仓库,它包含了绝大部分开源的构件。在默认配置下,当本地仓库没有maven需要的构件的时候,它就会尝试从中央仓库下载。私服是另一种特殊的远程仓库,为了节省带宽和时间,应该在局域网内架设一个私有的仓库服务器,用其代理所有外部的远程仓库内部的项目还能部署到私服上供其他项目使用。除了中央仓库和私服,还有很多其他公开的远程仓库,常见的有java.net Maven库(http://download.java.net/maven/2/)和jboss Maven库(http://repository.jboss.com/maven2/)等。

1.本地仓库
默认情况下,不管是在windows还是linux上,每个用户在自己的用户目录下都有一个路径名为.m2/repository/的仓库目录。有时候,因为某些原因(例如C盘空间不够),用户会想要自定义本地仓库目录地址。这时,可以编辑文件~/.m2/settings.xml设置localRepository元素的值为想要的仓库地址。例如:

Xml代码  

1. <settings>  

2.     <localRepository>D:\java\repository\</localRepository>  

3. </settings>  

这样,该用户的本地仓库地址就被设置成了D:\java\repository\。需要注意的是,默认情况下,~/.m2/settings.xml文件是不存在的,用户需要从Maven安装目录复制$M2_HOME/conf/settings.xml文件再进行编辑。
一个构件只有在本地仓库中之后,才能由其他Maven项目使用,那么构件如何进入到本地仓库中呢?最常见的是依赖Maven从远程仓库下载到本地仓库中。还有一种常见的情况是,将本地项目的构件安装到Maven仓库中。例如本地有两个项目A和B,两者都无法从远程仓库获得,而同时A又依赖于B,为了能构建A,B就必须首先得以构建并安装到本地仓库中。为了安装项目,我们可以在项目中执行: mvn clean install命令。Install插件的install目标将项目的构建输出文件安装到本地仓库

2.远程仓库
安装好Maven后,如果不执行任何Maven命令,本地仓库目录是不存在的。当用户输入第一条Maven命令之后,Maven才会创建本地仓库,然后根据配置和需要,从远程仓库下载构件至本地仓库。

3.中央仓库
由于最原始的本地仓库是空的,Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令的时候下载到需要的构件。中央仓库就是这样一个默认的远程仓库,Maven的安装文件自带了中央仓库的配置。读者可以使用解压工具打开jar文件$M2_HOME/lib/maven-model-builder-3.0.jar(在Maven2中,jar文件路径类似于$M2_HOME/lib/maven-2.2.1-uber.jar),然后访问路径:org/apache/maven/model/pom-4.0.0.xml,可以看到如下的配置:

Xml代码  

1. <repositories>  

2.     <repository>  

3.         <id>central</id>  

4.         <name>Maven Repository Switchboard</name>  

5.         <url>http://repo1.maven.org/maven2</url>  

6.         <layout>default</layout>  

7.         <snapshots>  

8.             <enabled>false</enabled>  

9.         </snapshots>  

10.    </repository>  

11.</repositories>  

包含这段配置的文件是所有Maven项目都会继承的超级POM。这段配置使用idcentral对中央仓库进行唯一标识,其名称为MavenRepository Switchboard,它使用default仓库布局。最后需要注意的是snapshots元素,其子元素enabled的值为false,表示不从该中央仓库下载快照版本的构件

4.私服
私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。此外,一些无法从外部仓库下载到的构件也能从本地上传到私服上供大家使用

远程仓库的配置

在很多情况下,默认的中央仓库无法满足项目的需求,可能项目需要的构件存在于另外一个远程仓库中,如:JBoss,Maven仓库。这时,可以在POM中配置该仓库,见代码请单:

 

Xml代码  

1. <project>  

2.   ...  

3.   <repositories>  

4.     <repository>  

5.       <id>jboss</id>  

6.       <name>JBoss Repository</name>  

7.       <url>http://repository.jboss.com/maven2/</url>  

8.       <releases>  

9.         <enabled>true</enabled>  

10.      </releases>  

11.    </repository>  

12.    <snapshots>  

13.      <enabled>false</enabled>  

14.    </snapshots>  

15.    <layout>default</layout>  

16.  </repositories>  

17.  ...  

18.</project>  

在repositories元素下,可以使用repository子元素声明一个或者多个远程仓库。该例中声明了一个id为jboss,名称为JBoss Repository的仓库。任何一个仓库声明的id必须是唯一的,尤其需要注意的是,maven自带的中央仓库使用的idcentral,如果其他的仓库声明也使用该id,就会覆盖中央仓库的配置。该配置中的url值指向了仓库的地址,一般来说,该地址都基于http协议,maven用户都可以在浏览器中打开仓库地址浏览构件。

该例配置中的releasessnapshots元素比较重要,它们用来控制Maven对于发布版构件和快照版构件的下载。该例中releasesenabled值为true,表示开启JBoss仓库的发布版本下载支持,而snapshotsenabled值为false,表示关闭JBoss仓库的快照版本的下载支持该例中的layout元素值default表示仓库的布局是Maven2Maven3的默认布局,而不是Maven1的布局

对于releases和snapshots来说,除了enabled,它们还包含另外两个子元素updatePolicychecksumPolicy:

 

Xml代码  

1. <snapshots>  

2.   <enabled>true</enabled>  

3.   <updatePolicy>daily</updatePolicy>  

4.   <checksumPolicy>ignore</checksumPolicy>  

5. </snapshots>  

元素updatePolicy用来配置Maven从远程仓库检查更新的频率,默认的值是daily,表示Maven每天检查一次。其他可用的值包括:never---从不检查更新;always---每次构建都检查更新;interval:X---每隔X分钟检查一次更新(X为任意整数)

元素checksumPolicy用来配置Maven检查检验和文件的策略。当构件被部署到Maven仓库中时,会同时部署对应的校验和文件。在下载构件的时候,Maven会验证校验和文件,如果校验和验证失败,怎么办?当checksumPolicy的值为默认的warn时,Maven会在执行构建时输出警告信息,其他可用的值包括:fail---Maven遇到校验和错误就让构建失败;ignore---使用Maven完全忽略校验和错误

 

1.远程仓库的认证

大部分远程仓库无须认证就可以访问,但有时候出于安全方面的考虑,我们需要提认证信息才能访问一些远程仓库。例如,组织内部有一个Maven仓库服务器,该服务器为每个项目都提供独立的Maven仓库,为了防止非法的仓库访问,管理员为每个仓库提供了一组用户名级密码。这时,为了能让Maven访问仓库内容,就需要配置认证信息。

配置认证信息和配置仓库信息不同,仓库信息可以直接配置在POM文件中,但是认证信息必须配置在settings.xml文件中。这是因为POM往往是被提交到代码仓库中供所有成员访问的,而settings.xml一般只放在本机。因此,settings.xml中配置认证信息更为安全。假设需要为一个id为my-proj的仓库配置认证信息,编辑settings.xml文件见代码清单: 

 

Xml代码  

1. <settings>  

2.   ...  

3.   <servers>  

4.     <server>  

5.       <id>my-proj</id>  

6.       <username>repo-user</username>  

7.       <password>repo-pwd</password>  

8.     </server>  

9.   </servers>  

10.  ...  

11.</settings>  

Maven使用settings.xml文件中并不显而易见的servers元素及其server子元素配置仓库认证信息。上例中,仓库的认证用户名为repo-user,认证密码为repo-pwd。这里的关键是id元素,settings.xmlserver元素的id必须与POM中需要认证的repository元素的id完全一致。换句话说,正是这个Id将认证信息与仓库配置联系在了一起。

 

2.部署至远程仓库

私服的一大作用是部署第三方构件,包括组织内部生成的构件以及一些无法从外部仓库直接获取的构件。无论是日常开发中生成的构件,还是正式版本发布的构件,都需要部署到仓库中,供其他团队成员使用。

Maven除了能对项目进行编译、测试、打包之外,还能将项目生成的构建部署到仓库中。首先,需要编辑项目的pom.xml文件。配置distributionManagement元素,见代码:

Xml代码  

1. <project>  

2.   ...  

3.   <destributionManagement>  

4.     <repository>  

5.       <id>proj-releases</id>  

6.       <name>Proj Release Repository</name>  

7.       <url>http://192.168.1.100/content/repositories/proj-releases</url>  

8.     </repository>  

9.     <snapshotRepository>  

10.      <id>proj-snapshots</id>  

11.      <name>Proj Snapshot Repository</name>  

12.      <url>http://192.168.1.100/content/repositories/proj-snapshots</url>  

13.    </snapshotRepository>  

14.  </destributionManagement>  

15.  ...  

16.</project>  

distributionManagement包含repositorysnapshotRepository子元素,前者表示发布版本构件的仓库,后者表示快照版本的仓库。这两个元素下都需要配置id、name和url,id为该远程仓库的唯一标识,name是为了方便人阅读,关键的url表示该仓库的地址。

往远程仓库部署构件的时候,往往需要认证。就是需要在settings.xml中创建一个server元素,其id与仓库的id匹配,并配置正确的认证信息。不论远程仓库下载构件,还是部署构件至远程仓库,当需要认证的时候,配置的方式是一样的。配置正确后,在命令行运行mvn clean deploy,Maven就会将项目构建输出的构件部署到配置对应的远程仓库,如果项目当前的版本是快照版本,则部署到快照版本仓库地址,否则就部署到发布版本仓库地址。

快照版本

在Maven的世界中,任何一个项目或者构件都必须有自己的版本。版本的值可能是1.0.0,1.3-alpha-4,2.0,2.1-SNAPSHOT或者2.1-20091214.221414-13。其中,1.0、1.3-alpha-4和2.0是稳定的发布版本,而2.1-SNAPSHOT和2.1-20091214.221414-13是不稳定的快照版本。

Maven为什么要区分发布版本和快照版本呢?简单的1.0.0、1.2、2.1等不就够了吗?为什么还要2.1-SNAPSHOT,甚至是长长的2.1-20091214.221414-13?试想一下这样的情况,小张在开发模块A的2.1版本,该版本还未正式发布,与模块A一同开发的还有模块B,它由小张的同事季MM开发,B的功能依赖于A。在开发的过程中,小张需要经常将自己最新的构建输出,交给季MM,供她开发和集成调试,问题是,这个工作如何进行呢?

如果不停更新版本2.1.1、2.1.2、2.1.3....呢?首先,小张和季MM两人都需要频繁地更改POM,如果有更多的模块依赖于模块A,就会涉及更多的POM更改;其次,大量的版本其实仅仅包含了微小的差异,这样也会造成为版本号的滥用。

Maven的快照版本机制就是为了解决上述问题。在该例中,小张只需要将模块A的版本设定为2.1-SNAPSHOT,然后发布到私服中,在发布的过程中,Maven会自动为构件打上时间戳。比如:2.1-20091214.221414-13就表示2009年12月14日 22点14分14秒的第13次快照。有了该时间戳,Maven就能随时找到仓库中该构件2.1-SNAPSHOT版本最新的文件。这时,季MM配置对于模块A的2.1-SNAPSHOT版本的依赖,当她构件模块B的时候,Maven会自动从仓库中检查模块A2.1-SNAPSHOT的最新构件,当发现有更新时便进行下载。默认情况下,Maven每天检查一次更新(由仓库配置的updatePolicy控制),用户也可以使用命令行-U参数强制让Maven检查更新,如:mvn clean install-U

基于快照版本机制,小张在构建成功之后才能将构件部署至仓库,而季MM可以完全不用考虑模块A的构建,并且她能确保随时得到模块A的最新可用的快照构件,而这一切都不需要额外的手工操作。

从仓库解析依赖的机制

Maven是根据怎样的规则从仓库解析并使用依赖构件的呢?

当本地仓库没有依赖构件的时候,Maven会自动从远程仓库下载。当依赖版本为快照版本的时候,Maven会自动找到最新的的快照。这背后的依赖解析机制可以概括如下:

1.当依赖的范围是system的时候,Maven直接从本地文件系统解析构件

2.根据依赖坐标计算仓库路径后,尝试直接从本地仓库寻找构件,如果发现相应构件,则解析成功。

3.在本地仓库不存在相应构件的情况下,如果依赖的版本是显式的发布版本构件,如:1.2,2.1等,则遍历所有的远程仓库,发现后,下载并解析使用。

4.如果依赖的版本是RELEASE或者LATEST,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/mavenmetadata.xml,将其与本地仓库的对应元数据合并后,计算出RELEASE或者LATEST真实的值,然后基于这个真实的值检查本地和远程仓库,如步骤1和3。

5.如果依赖的版本是SNAPSHOT,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/version/mavenmetadata.xml,将其与本地仓库的对应元数据合并后,得到最新快照版本的值,然后基于该值检查本地仓库,或者从远程仓库下载。

6.如果最后解析得到的构件版本是时间戳格式的快照,如:1.4-20091104.121450-121,则复制其时间戳格式的文件到非时间戳格式,如:SNAPSHOT,并使用该非时间戳格式的构件

当依赖的版本不明晰的时候,如:RELEASE,LATEST和SNAPSHOT,Maven就需要基于更新远程仓库的更新策略来检查更新。在前面的仓库配置blog中,有一些配置与此有关;首先是<releases><enabled>和<snapshots><enabled>,只有仓库开启了对于发布版本的支持时,才能访问该仓库的发布版本构件信息,对于快照版本也是同理;其次要注意的是

<releases>和<snapshots>的子元素<updatePolicy>,该元素配置了检查更新的频率。最后,用户还可以从命令行加入参数-U,强制检查更新,使用参数后,Maven就会忽略<updatePolicy>的配置。

当Maven检查完更新策略,并决定检查依赖更新的时候,就需要检查仓库元数据maven-metadata.xml。回顾一下前面提到的RELEASE和LATEST版本,它们分别对应了仓库中存在的该构件的最新发布版本和最新版本(包含快照),而这两个"最新"是基于groupId/artifactId/maven-metadata.xml计算出来的,如:

 

Xml代码  

1. <?xml version="1.0" encoding="UTF-8"?>  

2. <metadata>  

3.   <groupId>org.sonatype.nexus</groupId>  

4.   <artifactId>nexus</artifactId>  

5.   <versioning>  

6.     <latest>1.4.2-SNAPSHOT</latest>  

7.     <release>1.4.0</release>  

8.     <versions>  

9.       <version>1.3.5</version>  

10.      <version>1.3.6</version>  

11.      <version>1.4.0-SNAPSHOT</version>  

12.      <version>1.4.0</version>  

13.      <version>1.4.0.1-SNAPSHOT</version>  

14.      <version>1.4.1-SNAPSHOT</version>  

15.      <version>1.4.2-SNAPSHOT</version>  

16.    </versions>  

17.  </versioning>  

18.</metadata>  

在XML文件列出了仓库中存在的该构件所有可用的版本,同时latest元素指向了这些版本中最新的那个版本。而release元素指向了这些版本中最新的发布版本。Maven通过合并多个远程仓库及本地仓库的元数据,就能计算出基于所有仓库的latest和release分别是什么,然后再解析具体的构件。

需要注意的是,在依赖声明中使用LATESTRELEASE是不推荐的做法,因为Maven随时都可能解析到不同的构件,可能今天LATEST是1.3.6,明天就成了1.4.0-SNAPSHOT了,且Maven不会明确告诉用户这样的变化。当这种变化造成构建失败的时候,发现问题变得比较困难。RELEASE因为对应的是最新发布版构建,还相对可靠,LATEST就非常不可靠了,为此,Maven3不再支持在插件配置中使用LATESTRELEASE如果不设置插件版本,其效果就和RELEASE一样,Maven只会解析最新的发布版本构件。不过即使这样,也还存在潜在的问题。例如,某个依赖的1.1版本与1.2版本可能发布一些接口的变化,从而导致当前Maven构建失败。

当依赖的版本设为快照版本的时候,Maven也需要检查更新,这时,Maven会检查仓库元数据groupId/artifactId/version/maven-metadata.xml,如例: 

 

Xml代码  

1. <?xml version="1.0" encoding="UTF-8"?>  

2. <metadata>  

3.   <groupId>org.sonatype.nexus</groupId>  

4.   <artifactId>nexus</artifactId>  

5.   <version>1.4.2-SNAPSHOT</version>  

6.   <versioning>  

7.     <snapshot>  

8.       <timestamp>20091214.221414</timestamp>  

9.       <buildNumber>13</buildNumber>  

10.    </snapshot>  

11.    <lastUpdated>20091214221558</lastUpdated>  

12.  </versioning>  

13.</metadata>  

该xml文件的snapshot元素包含timestampbuildNumber两个子元素,分别代表了这一快照的时间戳和构建号,基于这两个元素可以得到该仓库中此快照的最新构件版本实际为1.4.2-20091213.221414-13。通过合并所有远程仓库和本地仓库的元数据,Maven就能知道所有仓库中该构件的最新快照。 

镜像

如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。换句话说,任何一个可以从仓库Y获得的构件,都胡够从它的镜像中获取。举个例子,http://maven.net.cn/content/groups/public/是中央仓库http://repo1.maven.org/maven2/在中国的镜像,由于地理位置的因素,该镜像往往能够提供比中央仓库更快的务。因此,可以配置Maven使用该镜像来替代中央仓库编辑settings.xml,代码如下:

 

Xml代码  

1. <settings>  

2.   ...  

3.   <mirrors>  

4.     <mirror>  

5.       <id>maven.net.cn</id>  

6.       <name>one of the central mirrors in china</name>  

7.       <url>http://maven.net.cn/content/groups/public/</url>  

8.       <mirrorOf>central</mirrorOf>  

9.     </mirror>  

10.  </mirrors>  

11.  ...  

12.</settings>  

该例中,<mirrorOf>的值为central,表示该配置为中央仓库的镜像任何对于中央仓库的请求都会转至该镜像,用户也可以使用同样的方法配置其他仓库的镜像。另外三个元素id,name,url与一般仓库配置无异,表示该镜像仓库的唯一标识符、名称以及地址。类似地,如果该镜像需认证,也可以基于该id配置仓库认证

关于镜像的一个更为常见的用法是结合私服。由于私服可以代理任何外部的公共仓库(包括中央仓库),因此,对于组织内部的Maven用户来说,使用一个私服地址就等于使用了所有需要的外部仓库,这可以将配置集中到私服,从而简化Maven本身的配置。在这种情况下,任何需要的构件都可以从私服获得,私服就是所有仓库的镜像。这时,可以配置这样的一个镜像,如例: 

 

Xml代码  

1. <settings>  

2.   ...  

3.   <mirrors>  

4.     <mirror>  

5.       <id>internal-repository</id>  

6.       <name>Internal Repository Manager</name>  

7.       <url>http://192.168.1.100/maven2</url>  

8.       <mirrorOf>*</mirrorOf>  

9.     </mirror>  

10.  </mirrors>  

11.  ...  

12.</settings>  

该例中<mirrorOf>的值为星号表示该配置是所有Maven仓库的镜像,任何对于远程仓库的请求都会被转至http://192.168.1.100/maven2/。如果该镜像仓库需要认证,则配置一个Id为internal-repository的<server>即可。为了满足一些复杂的需求,Maven还支持更高级的镜像配置:

1.<mirrorOf>*</mirrorOf>

匹配所有远程仓库。

2.<mirrorOf>external:*</mirrorOf>

匹配所有远程仓库,使用localhost的除外,使用file://协议的除外。也就是说,匹配所有不在本机上的远程仓库。

3.<mirrorOf>repo1,repo2</mirrorOf>

匹配仓库repo1和repo2,使用逗号分隔多个远程仓库。

4.<mirrorOf>*,!repo1</miiroOf>

匹配所有远程仓库,repo1除外,使用感叹号将仓库从匹配中排除。

需要注意的是,由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven仍将无法访问被镜像仓库,因而将无法下载构件。

仓库搜索功能

使用Maven进行日常开发的时候,一个常见的问题就是如何寻找需要的依赖,我们可能只知道城垛 要使用类库的项目名称,但添加Maven依赖要求提供确切的Maven坐标。这时就可以使用仓库搜索服务来根据关键字得到Maven坐标。下面列了四个仓库搜索服务:

 

1.Sonatype Nexus

地址:http://repository.sonatype.org/

 

2.Jarvana

地址:http://www.jarvana.com/jarvana/

 

3.MVNbrowser

地址:http://www.mvnbrowser.com

 

4.MVNrepository

地址:http://mvnrepository.com/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值