首页 > 代码库 > Maven学习笔记(五):仓库

Maven学习笔记(五):仓库

何为Maven仓库:

     在Maven世界中,任何一个依赖、插件或者项目构建的输出,都可以称为构件。例如,依赖log4j-1.2.15.jar是一个构件,插件maven-compiler-plugin-2.0.2.jar是一个构件。任何一个构件都有一组坐标唯一标识。
     得益于坐标机制,任何Maven项目使用任何一个构件的方式都是完全相同的。在此基础上,Maven可以在某个位置统一存储所有Maven项目共享的构件,这个统一的位置就是仓库。实际的Maven项目将不再各自存储其他依赖文件,它们只需要声明这些依赖的坐标,在需要的时候(例如,编译项目的时候需要将依赖加入到classpath中),Maven会自动根据坐标找到仓库中的构件,并使用它们。
     为了实现重用,项目构建完毕后生成的构件也可以安装或者部署到仓库中,供其他项目使用。
仓库的布局: 任何一个构件都有其唯一的坐标,根据这个坐标可以定义其在仓库中的唯一储存路径,这便是Maven的仓库布局方式。例如,log4j:log4j:1.2.15这个依赖,其对应的仓库路径为log4j/log4j/1.2.15/log4j-1.2.15.jar,细心的读者可以发现,该路径与坐标的大致对应关系为groupId/artifactId/version/artifactId-version(-classifier).packaging。

仓库的分类:

     对于Maven来说,仓库只有两类:本地仓库和远程仓库。当Maven根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件之后,下载到本地仓库再使用。如果本地仓库和远程仓库都没有需要的构件,Maven就会报错。
     有几类特殊的远程仓库。中央仓库是Maven核心自带的远程仓库,它包含了绝大部分开源的构件。在默认配置下,当本地仓库没有Maven需要的构件的时候,它就会尝试从中央仓库下载。私服是另一种特殊的远程仓库,为了节省带宽和时间,应该在局域网内架设一个私有的仓库服务器,用其代理所有外部的远程仓库。内部的项目还能部署到私服上供其他项目使用。除了中央仓库和私服,还有很多其他公开的远程仓库,常见的有Java.net Maven库和JBoss Maven库。
本地仓库:
     默认情况下,不管是Windows还是linux上,每个用户在自己的用户目录下都有一个路径名为.m2/repository/的仓库目录。注意,在Linux系统中,以点(.)开头的文件或目录默认是隐藏的,可以使用ls-a命令显示隐藏的文件或目录。
     有时候,因为某些原因(例如c盘空间不够),用户会想要自定义本地仓库目录地址。这时,可以编辑文件~/.m2/settings.xml,设置localRepository元素的值为想要的仓库地址。例如:
<Settings>
     <localRepository>D:\java\repository\</localRepository>
</settings>
     这样, 该用户的本地仓库地址就设置成了D:\java\repository。
中央仓库:
     中央仓库是Maven的默认使用的远程仓库,Maven的安装文件自带了中央仓库的配置。读者可以使用解压工具打开jar文件$M2_HOME/lib/maven-model-builder-3.0.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项目都会继承的超级POM,在后面会详细介绍继承和超级POM。这段配置使用的id central对中央仓库进行唯一标识,其名称是Maven repository Switchborad,它使用default仓库布局。最后需要注意的是snapshots元素,其子元素enabled的值为false,表示不从该中央仓库下载快照版本的构件。
     中央仓库包含了这个世界上绝大多数流行的开源Java软件,以及源码、作者信息、SCM、信息、许可证信息等。一般来说,一个简单的Maven所需要的所有依赖构件都能从中央仓库下载到。     
私服:
     私服是一种特殊的远程仓库,它是架设在局域网中的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。此外,一些无法从外部仓库下载到的构件也能从本地上传到私服上供大家使用(这点很重要,公司内部很多项目都是需要互通的,但是要求公司外部无法访问这些资源)。
     私服的好处类似于计算机上使用的缓存机制。详细来说有以下几点:
  • 节省自己的外网带宽:大量的对于外部仓库的重复请求会消耗很大的带宽,利用私服代理外部仓库之后,对外的重复构件下载便得以消除,即降低外网带宽的压力。
  • 加速Maven构建:不停地连接请求外部仓库是十分耗时的,使用私服可以很好的解决这一问题,当Maven只需要检查局域网内私服的数据时,构建的速度便能得到很大程度的提高。
  • 部署第三方构件:建立私服后,可以将内部构件部署到这个内部的仓库中,供内部的Maven项目使用。
  • 提高稳定性,增强控制:Maven构件高度依赖于远程仓库,因此,当Internet不稳定时,Maven的构建也会不稳定,甚至无法构建。使用私服,即使暂时没有Internet链接,Maven也能正常的使用。此外,一些私服软件(如nexus)还提供了很多额外的功能,如权限管理、REALEASE/SNAPSHOT分区等,管理员可以对仓库进行一些更高级的控制。
  • 降低中央仓库的负荷

远程仓库的配置:

     在很多情况下,默认的远程仓库无法满足项目的需求,可能项目需要的构件存在于另外一个远程仓库中,如JBoss Maven仓库。这时,可以在POM中配置该仓库(在settings.xml中可以配置远程仓库,其作用范围不同):
           
            <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>

     在repositories元素中,可以包含一个或多个用repository子元素声明的远程仓库。任何一个仓库使用id必须是唯一的,由于Maven使用的中央仓库id是central,如果其他仓库声明也使用了这个id,就会覆盖中央仓库的配置。该配置中的url值指向了仓库的地址,一般来说,该地址都基于http协议,Maven用户可以浏览器中打开仓库地址浏览构件。
     配置中的release和snapshots元素用来控制Maven对于发布版构件和快照版构件的下载。关于下面的enabled元素,如果enabled为true,则表示支持其对应的release或者snapshots版本下载,反之亦然。除了enabled,它们还包含另外两个子元素updatePolicy和checksumPolicy:
<snapshots>
     <enabled>true</enabled>
     <updatePolicy>daily</updatePolicy>
     <checksumPolicy>ignore</checksumPolicy>
</snapshots>
     元素updatePolicy用来配置Maven从远程仓库检查更新的频率,默认的值是daily,表示Maven每天检查一次。其他可用的值包括:never-从不检查更新;always-每次构建都检查更新;interval:X - 每隔X分钟检查一次更新(X为任意整数)。
     元素checksumPolicy用来配置Maven检查检验和文件的策略。当构件被部署到Maven仓库中时,会同时部署对应的检验和文件。checksumPolicy用来决定当下载构件时验证校验和失败所采取的策略:当checksumPolicy的值为默认的warn时,Maven会在执行构件时输出警告信息,其他可用的值包括:fail-Maven遇到检验和错误就让构件失败;ignore-使Maven完全忽略校验和错误。          
远程仓库的认证:
     大部分远程仓库不需要认证,有时出于安全考虑,比如某个公司自己搭建的远程仓库服务器,我们需要提供认证信息才能访问。这时,为了能让Maven访问仓库内容,就需要配置认证信息。
     配置认证信息和配置仓库信息不同,认证信息只能配置在settings.xml文件中,这是因为POM往往是被提交到代码仓库中供所有成员访问的,而setting.xml一般只放在本机。因此,在settings.xml中配置认证信息更为安全。
     假设需要一个id为my-proj的仓库配置认证信息,编辑settings.xml文件见代码如下:
<settings>
...
     <servers>
          <server>
               <id>my-proj</id>
               <username>repo-user</username>
               <password>repo-pwd</password>
          <server>
     <servers>     
...
</settings>
     settings.xml中server元素的id必须与POM中需要认证的repository元素的id完全一致。换句话说,正是这个id将认证信息与仓库配置联系在了一起。
部署至远程仓库:
     私服的一大作用是部署第三方构件,包括组织内部生成的构件以及一些无法从外部仓库直接获取的构件,供其他团队使用。
     首先,需要编辑项目的pom,xml文件。配置distributionManagement元素见代码如下:
<project>
...
     <distributionManagement>
          <repository>
               <id>proj-release</id>
               <name>Proj Release Repository</name>
               <url>http://192.168.1.100/content/repositories/proj-releases</url>
          </repository>
          <snapshotRepository>
               <id>proj-snapshots</id>
               <name>Proj Snapshot Repository</name>
               <url>http://192.168.1.100/content/repositories/proj-snapshots</url>
          </snapshotRepository>          
      <distributionManagement>
...
<project>
     distributionManagement包含repository和snapshotRepository子元素,前者表示发布版本构件的仓库,后者表示快照版本的仓库。这两个元素下都需要配置id、name和url,id为该远程仓库的唯一标识,那么是为了方便阅读,关键的url表示该仓库的地址。
     往远程仓库部署构件的时候,往往需要认证。简而言之,就是需要在settings,xml中创建一个server元素,其id与仓库的id匹配,并配置正确的认证信息。无论从远程仓库下载构件,还是部署构件至远程仓库,当需要认证的时候,配置的方式是一样的。
     配置正确后,在命令行运行mvn clean deploy,Maven就会将项目构建输出的构件部署到配置对应的远程仓库,如果项目当前的版本是快照版本,则部署到快照版本仓库地址,否则就部署到发布版本仓库地址。

快照版本:

     快照版本主要有两个作用。
     1. 用于区分稳定与不稳定的构件:那么发布版本就是稳定的,快照版本就是不稳定的。
     2. 用于避免由于版本升级导致不停地升级版本号,造成版本号的泛滥的问题。(这就是"快照"这个词的含义)。下面详细解释。
     举一个例子,假如现在需要将模块A的版本设定为2.1-SNAPSHOT,然后发布到私服中,在发布的过程中,Maven会自动为构件打上时间戳。比如2.1-20091214.221414-13就表示2009年12月14日22点14分14秒的第13次快照。有了该时间戳,Maven就能随时找到仓库中该构件2.1-SNAPSHOT版本最新的文件。这时,有B模块关于模块A的2.1-SNAPSHOT版本的依赖,当在构建B的时候,Maven会自动从仓库中检查模块A的2.1-SNAPSHOT的最新构件,当发现有更新时便进行下载。默认情况下,Maven每天检查一次更新(由仓库配置的updatePolicy控制),用户也可以使用命令行-U参数强制让Maven检查更新,如mvn clean install -U
     当项目经过完善的测试后需要发布的时候,就应该将快照版本更改为发布版本。例如,将2.1-SNAPSHOT更改为2.1,表示该版本已经稳定,且只对应了唯一的构件。相比之下,2.1-SNAPSHOT往往对应了大量的带有不同时间戳的构件,这也决定了其不稳定性。
     快照版本只应该在组织内部的项目或模块间依赖使用,因为这时,组织对于这些快照版本的依赖具有完全的理解及控制权。项目不应该依赖与任何组织外部的快照版本依赖,由于快照版本的不稳定性,这样的依赖会造成潜在的危险。也就是说,即使项目构建今天是成功的,由于外部的快照版本依赖实际对应的构件随时可能变化,项目的构建就可能由于这些外部的不受控制的因素而失败。
     

镜像:

     如果仓库X可以提供仓库Y储存的所有内容,那么就可以认为X是Y的一个镜像。换句话说,任何一个可以从仓库Y获得的构件,都能从它的镜像中获取。举个例子,http://maven.net.cn/content/groups/public是中央仓库http://repo1.maven.org/maven2/在中国的镜像,由于地理位置的因素,该镜像往往能够提供比中央仓库更快的服务。因此,可以配置Maven使用该镜像来替代中央仓库。编辑settings.xml:
<settings>
...
     <mirrors>
          <mirror>
               <id>maven.cn.cn</id>
               <name>one of the central mirrors in China</name>
               <url>http://maven.net.cn/content/groups/public</url>
               <mirrorOf>central</mirrorOf>
          </mirror>
     <mirrors>
...
<settings>
     该例中,<mirrorOf>的值为central,表示该配置为中央仓库的镜像,任何对于中央仓库的请求都会转至该镜像,用户也可以使用同样的方法配置其他仓库的镜像。          
     关于镜像的一个更常见的用法是结合私服。由于私服可以代理任何外部的公共仓库(包括中央仓库),因此,对于组织内部的Maven用户来说,使用一个私服地址就等于使用了所有需要的外部仓库,这可以将配置集中到私服,从而简化Maven本身的配置。在这种情况下,任何需要的构件都可以从私服获得,私服就是所有仓库的镜像。这时,可以配置这样的一个镜像,见代码如下:
 <settings>
...
     <mirrors>
          <mirror>
               <id>internal-repository</id>
               <name>Internal Repository Manager</name>
               <url>http://192.168.1.100/maven2</url>
               <mirrorOf>*</mirrorOf>
          </mirror>
     <mirrors>
...
<settings>
   
     该例中<mirrorOf>的值为星号,表示该配置是所有Maven仓库的镜像,任何对于远程仓库的请求都会被转至http://192.168.1.100/maven2/。如果该镜像仓库需要认证,则配置一个id为internal-repository的<server>即可。
Maven还支持更高级的镜像配置:
  • <mirrorOf>*</mirrorOf>:匹配所有远程仓库
  • <mirrorOf>external:*</mirrorOf>:匹配所有远程仓库,使用localhost的除外,使用file://协议的除外。也就是说,匹配所有不在本机上的远程仓库。
  • <mirrorOf>repo1,repo2</mirrorOf>:匹配仓库repo1和repo2,使用逗号分隔多个远程仓库
  • <mirrorOf>*,!repo1</mirrorOf>:匹配所有远程仓库,repo1除外,使用感叹号将仓库从匹配中排除
     需要注意的是,由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven仍将无法访问被镜像仓库,因而将无法下载构件。

Maven学习笔记(五):仓库