Maven实战学习笔记、6.仓库

来源:互联网 发布:犯罪现场调查 知乎 编辑:程序博客网 时间:2024/04/20 13:35

6.1 何为Maven仓库

    任何Maven项目使用任何一个构建的方式都是完全相同的。在此基础上,Maven可以在某个位置统一存储所有的Maven项目共享的构件,这个

统一的位置就是仓库。实际的Maven项目将不再各自存储其依赖文件、它们只需要声明这些依赖的坐标,在需要的时候(例如:编译项目的时候

需要将依赖加入到classpath中),Maven会自动根据坐标找到仓库中的构件,并使用它们。

    为了实现重用,项目构建完毕后生成的构件也可以安装或部署到仓库中,供其他项目使用。

6.2 仓库的布局

     任何一个构建都有其唯一的坐标,跟i据这个坐标可以定义仓库的存储路径 ,这就是maven仓库的布局方式,groupid/artifactId/version/artifactId-version.package。

6.3 仓库的分类

    仓库只分为两类:本地仓库和远程仓库。当Maven根据坐标寻找构建的时候,它首先会查看本地仓库,如果本地仓库存在构件,则
直接使用;如果本地仓库不存在构件或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件后,下载到
本地仓库在使用。如果本地仓库与远程仓库都没有需要的构件,Maven就会报错。

    在这个最基本分类基础上,还有必要介绍一些特殊的远程仓库。中央仓库是Maven核心自带的远程仓库,它包含了大部分开源的构件。在默认的配置下,

当本地仓库没有Maven需要的构件的时候,它就会尝试从中央仓库下载。

    私服是另一种特殊的远程仓库,为了节省宽带和时间,应该在局域网内架设一个私有的仓库服务器,用其代理所有的外部远程仓库。内部的项目还能

部署到私服上供其他项目使用。

  除了中央仓库和私服,还有很多其他公开的远程仓库。

                                                                maven仓库  

                                                本地仓库                    远程仓库

                                                                      中央仓库   私服   其他公共的库

6.3.1 本地仓库

    一般来说,在Maven项目目录下,没有诸如lib/这样用来存放依赖文件的目录。当Maven在执行编译或测试时,如果需要使用依赖文件,它总是基于坐标

使用本地仓库的依赖文件。

    默认情况下,不管是在windows还是linux上,每个用户在自己的用户目录下都有一个路径名.m2/repository的仓库目录。

   但是有些时候,录入C盘空间不够,用户可以自定义本地仓库目标地址。这时,可以编辑文件setting.xml,例如我本地的setting.xml的路径为

C:\Users\Administrator\.m2\settings.xml,添加配置:

<settings >  <localRepository>D:\path\to\local\repo</localRepository><span style="font-family:Arial, Helvetica, sans-serif;"> <settings></span>
这样就将本地仓库地址就被设置成了D:\path\to\local\repo;

    需要注意的是,默认情况下,~/.m2/settings.xml文件是不存在的,用户需要从Maven安装目录复制$M2_HOME/conf/settings.xml文件再进行编辑。

    一个构件只有在本地仓库中之后,才能由其他Maven项目使用,那么构件如何进入到本地仓库中呢?最常见的是依赖Maven从远程仓库下载到本地

仓库。还有一种常见的情况是,将本地项目的构件安装到Maven仓库中。例如,本地有两个项目A和B,两者都无法从远程仓库获得,而同时A又依赖B,

为了能构建A,B就必须首先得以构建并安装到本地仓库中,执行mvn clean install命令,就能看到生成jar包及其安装在本地仓库的路径。使用install插件

将生成的文件复制到本地仓库,具体的路径通过坐标来计算得出。

6.3.2  远程仓库

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

6.3.3 中央仓库

     由于最原始的本地仓库是空的,Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令的时候下载到需要的构件。中央仓库就是这样
一个默认的远程仓库,Maven的安装文件自带了中央仓库的配置。默认的中央仓库的配置可以在超级pom里面看到。

6.3.4 私服

        私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载
构建的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。此外,一
些无法从外部仓库下载到的构件也能从本地上传私服上供大家使用。
        即使是一台直接连入internet的个人机器上使用maven,也应该在本地建立私服。因此私服可以帮助你:
节省自己的外网带宽。 建立私服同样可以减少组织自己的开支,大量的对于外部仓库的重复请求会消耗很大的带宽,利用私服代理外部仓库之后,对外
       的重复构件下载便得以消除,即降低外网带宽的压力。
加速Maven的构件。不停地连接请求外部仓库是十分耗时的,但是Maven的一些内部机制(如快照更新检查)要求Maven在执行构建的时候不停地检查
      远程仓库数据。因此,当项目配置了很多外部远程仓库的时候,构建的速度回被大大降低。使用私服可以很好地解决这一问题,当Maven只需要检查
局域网内私服的数据时,构建速度便能得到很大程度的提高。
部署第三方构件。当某个构件无法从任何一个外部远程仓库获得,怎么办?这样的例子很多,如组织内部生成的私有构件肯定无法从外部仓库获得、
Oracle的JDBC驱动由于版权因素不能发布到公共仓库。建立私服之后,便可以将这些构件部署到这个内部的仓库中,供其内部项目使用。
提高稳定性,增强控制。Maven构件高度依赖于远程仓库,因此,当Internet不稳定的时候,Maven构件也会变得不稳定,甚至无法构建。使用私服
   后,及时暂时没有Internet连接,由于私服已经缓存了大量构建,Maven也仍然可以正常运行。此外,一些私服软件(如Nexus)还提供了很多
  额外的功能,如权限管理,RELEASE/SNAPSHOT区分等。管理员可以对仓库进行一些更高级的控制。
降低中央仓库的负荷。运行并维护一个中央仓库不是一件容易的事情,服务数百万的请求,请求数T的数据,需要相当大的财力。使用私服可以避免很多
对中央仓库的重复下载,想象一下,一个有数百位开发人员的公司,在不使用私服的情况下,一个构件往往会被重复下载数百次;建立私服之后,这几百次
下载只会发生在内网范围内,私服对于中央仓库只有一次下载。
后面会介绍最流行的私服软件-Nexus。

6.4 远程仓库的配置

        在很多情况下,默认的中央仓库无法满足项目的需求,可能项目需要的构件存在于另外一个远程仓库中,如JBoss Maven仓库。这时,可以在POM中
配置该仓库。
  <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为jboss,名称为JBoss Repository的仓库。任何一个
仓库声明的id必须是唯一的,尤其需要注意的是,Maven自带的中央仓库使用的id为central,如果其他的仓库声明也使用该id,就会覆盖中央仓库的配置。
该配置中的url值指向了仓库的地址,一般来说,该地址都基于http协议,Maven用户都可以在浏览器中打开仓库地址浏览构件。
        该例配置中的releases和snapshots元素比较重要,它们用来控制Maven对于发布版构件和快照版构件的下载。关于快照版本,在6.5节会详细解释。这
里需要注意的是enabled子元素,该例中releases的enabled值为true,标识开启JBoss仓库的发布版本下载支持,而snapshots的enabled值为false,表示
关闭JBoss仓库的快照版本的下载支持。因此,根据该配置,Maven只会从JBoss仓库下载发布版的构件。
        该例中的layout和snapshots来说,除了enabled,它们还包含两个子元素updatePolicy和checksumPolicy:
          <snapshots>             <enabled>false</enabled>             <updatePolicy>daily</updatePolicy>             <checksumPolicy>ignore</checksumPolicy>          </snapshots>
        元素updatePolicy用来配置Maven从远程仓库检查更新的频率,默认的值是daily,表示Maven每天检查一次。其他可用的值包括:never-从不检查更新;
always-每i此次构建都检查更新;interval:X-每隔X分钟检查一次更新(X为任意整数)。
        元素checksumPolicy用来配置Maven检查检验和文件的策略。当构件被部署到Maven仓库中时,会同时部署对应的校验和文件。在下载构件的时候,Maven
会验证校验和文件,如果校验和验证失败,怎么办?当checksumPolicy的值默认为warn时,Maven会在执行构件时输出警告信息,其他可用的值包括:fail-Maven
遇到校验和错误就让构建失败;ignore-使Maven完全忽略校验和错误。

6.4.1 远程仓库的认证

        大部分远程仓库无需认证就可以访问,但有时候出于安全方面的考虑,我们需要提供认证信息才能访问一些远程仓库。例如,组织内部有一个Maven仓库服务
器,该服务器为每个项目提供一个独立的Maven仓库,为了防止非法的仓库访问,管理员为每个仓库提供了一组用户名和密码。这时,为了能让Maven访问仓库内
容,就需要配置认证信息。
       配置认证信息与配置仓库信息不同,仓库信息可以直接配置在pom文件中,但是认证信息必须配置在settings.xml文件中。这是因为POM往往是被提交到代码仓库
中供所有成员访问的,而settings.xml一般放在本机。因此,在settings.xml中配置认证信息更为安全。
       假设需要为一个id为deploymentRepo的仓库配置认证信息。
<settings>  
<servers>    <server>      <id>deploymentRepo</id>      <username>repouser</username>      <password>repopwd</password>    </server>  </servers>
<settings>
       Maven使用settings.xml文件中并不显而易见的servers元素及其server子元素配置仓库认证信息。该仓库的认证用户名为repouser,认证密码为repopwd。这里的关键
是id元素,settings.xml中server元素的id必须与POM中需要认证的repository元素的id完全一致。换句话说,正是这个id将认证信息与仓库配置联系在了一起。

 6.4.2 部署至远程仓库

        私服的一大作用是部署第三方构件,包括组织内部生成的构件以及一些无法从外部仓库直接获取的构件。无论是日常开发中生成的构件,还是正式版本发布的构件,
都需要部署到仓库中,供其他团队成员使用。
        Maven除了能对项目进行编译、测试、打包之外,还能将项目生成的构见部署到仓库中。首先,需要编辑项目的pom.xml文件。配置distributionManagement,
  <distributionManagement>      <repository>          <id>proj-releases</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>
        distributionManagement包含repository和snapshotRepository子元素,前者表示发布版本构件的仓库,后者表示快照版本的仓库。关于发布版本和快照版本,第6.5
节会详细解释。这两个元素都需要配置id、name、url,id为该远程仓库的唯一标识,name是为了方便人阅读,关键的url表示该仓库的地址。
       往远程仓库部署构件的时候,往往需要认证。配置认证的方式已在第6.4.1节中详细阐述,简而言之,就是需要在settings.xml中创建一个server元素,其id与仓库的id
匹配,并配置正确的认证信息,无论从远程仓库下载构件,还是部署构件至远程仓库,当需要认证的时候,配置的方式是一样的。
       配置正确后,在命令行运行mvn clean deploy,Maven就会将项目构建输出的构件部署到配置对应的远程仓库,如果项目当前的版本是快照版本,则部署到快照版本
仓库地址,否则就部署到发布版本仓库地址。

6.5 快照版本

        在Maven的世界中,任何一个项目或it构件都必须有自己的版本。版本可能是1.0.0、1.3-alpha-4、2.0、2.1-SNAPSHOT。其中,1.0.0、1.3-alpha-4和2.0都是
稳定的版本,而2.1-SNAPSHOT是不稳定的快照版本。
        Maven为什么要区分发布版和快照版。试想一下这样的情况,小张在开发A的2.1版本,该版本还未发布,与模块A一同开发的还有模块B,它由小张的同事季MM
开发,B的功能依赖于A。在开发的过程中,小张需要经常将自己最新的构建输出,交给季MM,供他开发和集成调试,问题是,这个工作如何进行呢。
1、方案一
        让季MM自己签出模块A的源码进行构建。这种方法能够确保季MM得到模块A的最新构件,不过她不得不去构建模块A。多了一些版本的控制和Maven操作还不算,
当构建A失败的时候,他还会一头雾水,最后不得不找小张解决。显然这种方式是低效的。
2、方案二
       重复部署模块A的2.1版本供版本季MM下载。虽然小张能够保证仓库中的构件是最新的。但对于Maven来说,同样版本和同样的坐标就意味着同样的构件。因此,
如果季MM在本机的本地仓库包含了模块A的2.1版本构件,Maven就不会再对照远程仓库进行更新。除非她每次执行Maven命令之前,清除本地仓库,但这种要求手
工干预的做法显然也是不可取得。
3、方案三
        不停更新版本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-SNAPHOT
版本最新的文件快照。季MM配置对于模块A的2.1--SNAPSHOT版本的依赖,当她构建模块B的时候,Maven会自动从仓库中检查模块A的2.1-SNAPSHOT的最新构件,当
发现有更新时便进行下载。默认情况下。Maven每天检查一次更新(由仓库配置的updatePolicy控制),用户也可以使用命令-U 参数强制让Maven检查更新,如mvn clean
install -U。
       基于快照版本机制,小张在构建成功之后才能将构件部署到仓库,而季MM可以完全不考虑模块A的构建,并且她能确保随时得到模块A的最新可用的快照构件,而这一
切都不需要额外的手工操作。
      当项目经过完善的测试后需要发布的时候,就应该将快照版本更改为发布版本。例如将2.1-SNAPSHOT更改为2.1,表示该版本已经稳定,且只对应了唯一的构件。相比
之下,2.1-SNAPSHOT往往对应了大量的带来不同时间戳的构件,这也决定了其不稳定性。
       快照版本只应该在组织内部的项目或模块间依赖使用,因此这时,组织对于这些快照版本的依赖具有完全的理解及控制权。项目不应该依赖于任何外部组织的快照版本
依赖,由于快照版本的不确定性。这样的依赖会造成潜在的危险。也就是说,即使项目构建今天是成功的,由于外部的快照版本依赖实际对应的构件随时可能变化,项目
的构建就可能由于这些外部的不受控制的因素而失败。

6.6 从仓库解析依赖的机制

      Maven是根据怎样的规则从仓库解析并使用依赖的构件的呢。
      当本地仓库没有依赖构件的时候,Maven会自动从远程仓库下载,当依赖版本为快照版本的时候,Maven会自动找到最新的快照。这背后的依赖机制可以概括如下:
1)当依赖范围是system的时候,Maven直接从本地文件解析构件。
2)根据依赖坐标计算仓库路径后,尝试直接从本地仓库寻找构件,如果发现相应构件,则解析成功。
3)在本地仓库不存在相应构件的情况下,如果依赖的版本是显式的发布版本构件,如1.2、2.1-beta-1等,则遍历所有的远程仓库,发现后,下载并解析使用。
4)如果依赖的版本是RELEASE或者LATEST,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/maven-metadata.xml,则其与本地仓库的对应元
      数据合并后,得到最新快照版本的值,然后基于该值检查本地仓库,或者从远程仓库下载。
5)如果依赖的版本是SNAPSHOT,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/version/maven-metadata.xml,将其与本地仓库对应的元数据
      合并后,得到最新快照版本的值,然后基于该值检查本地仓库,或者从远程仓库下载。
6)如果最后解析得到的构件版本是时间戳格式的快照,如1.4.1-20091104.121450-121,则复制其时间戳格式的文件至非时间戳格式,如SNAPSHOT,并使用
      该非时间戳格式的构件。
      当依赖的版本不明晰的时候,如RELEASE、LATEST和SNAPSHOT,Maven就需要基于更新远程仓库的更新策略来检查更新。在第6.4节提到的仓库配置中,
有一些配置与此有关:首先<releases><enabled>和<snapshots><enabled>,只有仓库开启了对于发布版本的支持时,才能访问该仓库的发布版本构件信息,
对于快照版本也是同理;其次要注意的是<releases>和<snapshots>的子元素<updatePolicy>,该元素配置了检查更新的频率,每日检查更新,永远检查更新、
从不检查更新、自定义时间间隔检查更新等。最后,用户还可以从命令行加入参数-U,强制检查更新,使用参数后,Maven就会忽略<updatePolicy>的配置。
       当Maven检查更新策略,并决定检查依赖更新的时候,就需要检查仓库元数据maven-metadata.xml。
       回顾一下前面提到的RELEASE和LATEST版本,它们分别对应了仓库中存在的该构件的最新发布版本和最新版本(包含快照),而这两个“最新”是基于
maven-metadata.xml计算出来的。
     latest元素指向了这些版本中最新的那个版本,release元素指向版本中最新的发布版本。
      需要注意的是,在依赖声明中使用LATEST和RELEASE是不推荐的做法,因为Maven随时都可能解析到不同的构件,可能今天LATEST是1.3.6,明天可能
就成为1.4.0-SNAPSHOT了,且Maven不会明确告诉用户这些变化。当这种变化造成构建失败的时候,发现问题会变得比较困难。RELEASE因为对应的是最
新发布版构件,还相对可靠,LATEST就非常不可靠了,为此,Maven3不在支持在插件配置中使用LATEST和RELEASE。如果不设置插件版本,其效果就
和RELEASE一样,Maven只会解析最新的发布版本的构件。不过即使这样,也还存在潜在的风险。例如,某个依赖1.1版本与1.2版本可能发生一些接口的变化。
从而导致当前Maven构建失败。
       当依赖的版本设为快照版本的时候,Maven也需要检查更新,这时,Maven会检查仓库元数据。
       最后,仓库元数据并不永远正确的,有时候当用户发现无法解析某些构件,或者解析得到错误构件的时候,就有可能出现仓库元数据有误,这时就需要手工
地,或者使用工具(nexus)对其进行修复。

6.7 镜像

       如果仓库X可以是Y的一个镜像。换句话说,任何一个可以从仓库Y获得的构件,都能够从它的镜像中获取。举个例子,http://maven.net.cn/content/group/public/
是中央仓库http://repo1.maven.org/maven2/在中国的镜像,由于地理位置的因素,该镜像往往能够提供比中央仓库更快的服务。因此,可以配置Maven使用该镜像
来替代中央仓库。
<mirrors>    <!-- mirror     | Specifies a repository mirror site to use instead of a given repository. The repository that     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.     |    <mirror>      <id>mirrorId</id>      <mirrorOf>central</mirrorOf>      <name>Human Readable Name for this Mirror.</name>      <url>http://maven.net.cn/content/group/public/</url>    </mirror>     -->  </mirrors>
       该例中,<mirrorOf>的值为central,表示该配置为中央仓库的镜像,任何对于中央仓库的请求都会转至该镜像,用户也可以使用同样的方法配置其他仓库的镜像。另外三个
元素id、name、url与一般仓库配置无异,表示该镜像仓库的唯一标识,名称和地址。类似地,如果该镜像需要认证,也可以基于该id配置仓库认证。
       关于镜像的一个更为常见的用法是结合私服。由于私服可以代理任何外部的公共仓库(包括中央仓库),因此,对于组织内部的Maven用户来说,使用一个私服地址就
等于使用了所有的所需要的外部仓库,这可以将配置集中到私服,从而简化Maven本身的配置。在这种情况下,任何需要的构件都需要从私服获得,私服就是所有仓库的镜像。
这是,可以配置这样一个镜像。
<mirrors>    <!-- mirror     | Specifies a repository mirror site to use instead of a given repository. The repository that     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.     |    <mirror>      <id>mirrorId</id>      <mirrorOf>*</mirrorOf>      <name>Human Readable Name for this Mirror.</name>      <url>http://maven.net.cn/content/group/public/</url>    </mirror>     -->  </mirrors>

6.8 仓库搜索服务

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

6.8.1 Sonatype  Nexus

       地址:http://repository.sonatype.org/
       Nexus是当前最流行的开源Maven仓库管理软件,本书后面会有专门的章节讲述如何使用Nexus架设私服。这里要介绍的是Sonatype架设的一个公共Nexus仓库实例。
       Nexus提供了关键字搜索、类名搜索、坐标搜索、校验和搜索服务等功能。搜索后,页面清晰地列出了结果构件的坐标及所属仓库。用户可以直接下载相应构件,还可以
直接复制根据坐标自动生成的xml依赖声明。

6.8.2 Jarvana

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

6.8.3 MVNerbrows

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

6.8.4   MVNrepository

   地址:http://mvnrepository.com/



0 0
原创粉丝点击