Maven仓库详解

概念理解

1. 构件

在Maven世界中,任何一个依赖、插件或者项目构建的输出,都可以称为构件。如依赖log4j-1.2.15.jar是一个构件,插件maven-compiler-plugin-2.0.2.jar是一个构件。

2. 坐标

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仓库详解_第1张图片

Maven仓库的分类

3.1 本地仓库

本地仓库是指用户本机中的的仓库,一般在Maven项目中,没有lib/这样的依赖文件的目录。当Maven项目进行编译和运行的时候,需要的依赖文件必须在本地仓库中存在才可以被Maven项目所使用。

3.1.1 默认仓库位置

本地仓库默认位置在${user.home}/.m2/repository目录下。假设我的用户名为Dong,那么在Windows中仓库地址为C:\Users\Dong\.m2\repository,而Linux上的本地仓库地址为home/Dong/.m2/repository/。

注意:Liunx中以点(.)开头的文件或目录默认隐藏的,可以使用ls-a命令查看。

3.1.2 修改仓库位置

可以通过编辑Maven的配置文件:settings.xml,设置localRepository元素的值为想要的仓库地址。如:

<settings>
    <localRepository>D:\Soft\maven\maven_jar\repositorylocalRepository>
settings>

此时,用户的本地仓库就被设置成了D:\Soft\maven\maven_jar\repository

3.1.3 三种方式添加构件到本地仓库

3.1.3.1 从远程仓库下载

通过在项目的pom中配置依赖,dependency下载需要的依赖到本地仓库。

3.1.3.2 通过maven命令安装构件到本体仓库

在某个maven项目根目录下执行:mvn clean install命令就可以把项目以构件形式安装到本地仓库中

3.2.2.3 安装第三方构件到本地仓库

别人开发好的一个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

3.2 远程仓库

远程仓库相对本地仓库,本地仓库不存在的构件才会从远程仓库下载,并保存在本地仓库中。对maven来说,每个用户只有一个本地仓库,但可以配置访问很多远程仓库。

3.2.1 中央仓库

由于最原始的本地仓库是空的,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>

解释:

  1. 使用id=central对仓库进行唯一标识;
  2. name表示仓库名称;
  3. url为仓库地址;
  4. layout=default指定仓库的布局,default也就是上面提到布局规则;
  5. enabled=false表示不从该中央仓库下载快照版本的构件。

3.2.2 私服

私服是一种特殊的远程仓库,它是架设在局域网的仓库服务,私服代理广域网上的远程仓库,供局域网使用。
Maven仓库详解_第2张图片

私服的用途

私服的好处:

  • 节省资金的外网带宽,利用私服代理外部仓库之后,对外的重复构件下载便得以下手,降低外网带宽压力。
  • 加速Maven构建。不停地连接请求外部仓库是什么耗时的,但是maven的一些内部机制(如快照更新检查)要求Maven在执行构建的时候不停地检查远程仓库数据。因此,当项目配置了很多外部远程仓库的时候,构建速度会降低。使用私服解决这问题,因为Maven只需要检查局域网内私服的数据时,构建速度便提高。
  • 部署第三方构件,当某个构件无法从任何一个远程仓库获取怎么办?比如Oracle的JDBC驱动由于版权原因不能发布到公共仓库中。建立私服后,便可以将这些构件部署到这个内部仓库中,供内部Maven项目使用。
  • 提高稳定性,增强控制。对于远程仓库当外网不可用时,maven构建有可能因为依赖没有下载而不可行,私服后,即使没有网,如果该构件只有之前被其它人下载过就会存在私服上,此时我下时就可以不用连接外网直接就可以从私服上下载到。同时私服软件(nexus)还提供了额外的管理功能。
  • 降低中央仓库的负荷

3.2.2 在pom文件中配置远程仓库

默认的中央仓库无法满足项目需求,可能需要的构件在另外一个远程仓库,如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的仓库。

注意:

  1. id要唯一,如果出现重复会覆盖掉之前的。
  2. 对于releasesenabled=true表示开启JBoss仓库的发布版本下载支持。根据以上配置,maven只从JBoss仓库下载发布版本的构件不会下载快照版本。
  3. 对于releases和snapshots来说,除了enabled还包含两个子元素updataPolicy和checksumPolicy:
<releases>
      <enabled>trueenabled>
      <updataPolicy>dailyupdataPolicy>
      <checksumPolicy>warnchecksumPolicy>
  releases>
  • **updataPolicy:配置maven从远程仓库检查更新的频率,对同一个版本(如:log4j.1.2.15.jar)**的构件如果发现有更新(如:对log4j.1.2.15.jar进行了内容修复但是版本都不变)会下载最新的。默认daily-maven每天检查一次
    never-从不检查;always-每次构件都要检查更新;interval:X -每隔X分钟检查一次更新(X为整数)
    当然:用户可以使用参数-U,强制检查更新,使用参数后,maven就会忽略updatePolicy的配置。
    至于如何更新请看下面的(从仓库解析依赖的机制),其中涉及到从远程下载maven-metadata.xml文件
  • **checksumPolicy:**用来配置Maven检查校验和文件失败后的策略。构件被部署到maven仓库中时会同时部署对应的校验和文件,maven会验证校验和文件以确定下载的构件是否完整,如果校验失败,怎么办?策略有3中:(默认值)warn-maven会执行构建时输出警告信息;fail-maven遇到校验和错处就让构建失败;ignore-使maven完全忽略校验和错误。

3.2.3 远程仓库的认证

有时候处于安全考虑,需要提供认证信息才能访问一些远程仓库。为了能让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.xmlservers中就是用来配服务器授权信息的,当然不仅可以配置仓库服务器认证信息,还可以配置其它的比如tomcat服务器授权信息也可以在这里配置。

3.2.4 在settings.xml文件中配置仓库镜像

如果仓库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>
  • 该例中mirrorOfcentral,表示该配置为中央仓库的镜像,任何对于中央仓库的请求都会转至该镜像,用户也可以使用该方法配置其它仓库的镜像。另外三个参数和配置一般远程仓库一样。
  • 镜像一般用在私服上,因为私服代理了任何外部的公共仓库,因此对于组织内部的maven用户来说,使用一个私服地址就等于使用所有外部仓库。
  • 为满足复杂需求,maven支持更高级的镜像配置。
  • * :匹配所有远程仓库。
  • external:* :匹配所有远程仓库,使用 localhost 的除外,使用file://协议的除外。
  • repo1,repo2 :匹配仓库repo1,repo2,多个使用逗号分隔。
  • *,!repo1 :匹配所有远程仓库,repo1除外。

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

四、从仓库解析依赖的机制

  1. 当依赖范围是 system 时候,Maven直接从本地文件解析构件。
  2. 根据依赖坐标计算仓库路径后,先从本地仓库寻找构件,如果发现则解析成功。
  3. 本地仓库没找到,如果依赖版本(version)是发布版构件,即1.2,2.3等,则遍历远程仓库,发现后下载并解析使用。
  4. 如果version是SNAPSHOT版,如:2.1-SNAPSHOT,则基于更新策略(updatepolicy)读取所有远程仓库的元数据groupId/artifactId/version/maven-metadata.xml,将其与本地仓库的对应元数据合并后,得到最新快照版本的值,然后基于该值检查本地仓库,或者从远程仓库下载。(如果最新版还是之前的值就不需要去远程仓库下载了)。
    注意:这一步因为updatepolicy的原因,可能要求本机能连接到远程仓库(远程仓库可以是私服或者中央仓库,一般只有自己的项目会使用SNAPSHOT,所以大多数是私服)
  5. 如果最后解析得到构件版本是时间戳格式的快照,如1.4.1-20161121.121432-121则复制其时间戳格式的文件至非时间戳格式,如SNAPSHOT,并使用该时间戳格式的构件。
  6. 当依赖的version值为RELEASE时(不建议),Maven会基于updatepolicy策略读取远程仓库的元数据groupId/artifactId/maven-metadata.xml,将其与本地仓库相对应元数据合并后,计算出最新版本的RELEASE值(稳定版),然后基于这个值检查本地和远程仓库,步骤如2和3。
    注意:存在潜在问题,如某个依赖的1.1版本与1.2版本可能发生一些接口变化,从而导致当前Maven项目构建失败,所以依赖的版本最好确定

你可能感兴趣的:(其他)