Maven仓库优先级以及失败机制分析

Maven对后端开发的人员来说并不陌生,但多数情况下也仅仅只是配置了镜像地址用来下载依赖包。真正遇到难解的问题,还是得要稍微深入理解一些知识例如POM、坐标、仓库、生命周期等原理,这里推荐《Maven实战》这本书,虽然很老但是很经典。

今天想总结一下仓库的优先级和失败机制的问题,启发内容来自于这篇博客:Maven仓库理解和优先级,作者的核心观点大致如下:

本地仓库 > 私服 (profile)> 远程仓库(repository)和 镜像 (mirror) > 中央仓库 (central)

镜像是一个特殊的配置,其实镜像等同与远程仓库,没有匹配远程仓库的镜像就毫无作用。所以 maven 仓库真正的优先级为:

            本地仓库 > 私服(profile)> 远程仓库(repository)


接下来,通过实战进行验证和理解:

1、初始化Maven项目

首先,有两个点需要提出:

  • IDEA中的maven-reimport指令,默认使用的是用户级别的settings.xml配置,但是只在background tasks中执行,报错信息不明显,因此不推荐;而命令行中以mvn执行的指令,默认使用全局的settings.xml配置,可以通过在conf文件夹下的m2.conf文件中进行配置。

  • 因此,一般是推荐全局配置和用户配置保持一致,或者IDEA调整User Settings file的配置,本文采用后者(根据实际情况判断,也有可能因为配置了环境变量等原因,命令行默认使用用户配置)。

Maven仓库优先级以及失败机制分析_第1张图片

settings.xml中内容如下,没有配置镜像中央仓库,但是配置了私服(jdk1.7-Mac下使用Nexus搭建Maven私服,jdk-1.8-Mac安装配置nexus3.0):



  
  
  
  
  
    
      mymaven
      
        
          nexus maven
          http://localhost:8081/repository/maven-public/
          true
          true
        
      
    
  
  
    mymaven
  

pom.xml中的依赖和仓库配置如下:




  4.0.0
  com.mavenTest
  MavenTest
  1.0-SNAPSHOT

  
    
      org.springframework
      spring-core
      4.3.1.RELEASE
    
  

  
    
      jboss maven
      http://repository.jboss.org/nexus/content/groups/public/
      
        true
      
      
        true
        always
        fail
       
     
  

命令行中使用"mvn clean install"指令,失败了,报错如下:

Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:15 min
[INFO] Finished at: 2018-09-19T00:45:43+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Plugin org.apache.maven.plugins:maven-clean-plugin:2.5 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-clean-plugin:jar:2.5: Could not transfer artifact org.apache.maven.plugins:maven-clean-plugin:pom:2.5 from/to central (https://repo.maven.apache.org/maven2): Connect to repo.maven.apache.org:443 [repo.maven.apache.org/151.101.40.215] failed: Operation timed out -> [Help 1]

虽然配置的私服中有该插件,但是clean插件还是选择了默认的中央仓库下载(因为没有配置中央镜像),而因为网络问题最终导致了失败。这有两种可能,一种就是中央仓库的优先级高于profile中定义的私服和pom中定义的其他远程仓库,另一种则是只有插件是默认使用远程仓库下载的。

2、私服与中央仓库的优先级比较

按照如上的推理,可以通过在全局settings.xml中增加阿里云中央镜像,然后下载插件和pom中的依赖包,观察输出信息从而得出结论。

添加了阿里云中央镜像的settings.xml内容如下:



  
  
  
  
    
      alimaven
      aliyun maven
      http://maven.aliyun.com/nexus/content/groups/public/
      central
    
  
  
    
      mymaven
      
        
          nexus maven
          http://localhost:8081/repository/maven-public/
          true
          true
        
      
    
  
  
    mymaven
  

pom中内容保持不变,执行命令行 "mvn clean install",最终build success,关键信息如下:

Downloading from alimaven: http://maven.aliyun.com/nexus/content/groups/public/org/apache/maven/plugins/maven-install-plugin/2.4/maven-install-plugin-2.4.jar
Downloaded from alimaven: http://maven.aliyun.com/nexus/content/groups/public/org/apache/maven/plugins/maven-install-plugin/2.4/maven-install-plugin-2.4.jar (27 kB at 106 kB/s)
Downloading from nexus maven: http://localhost:8081/repository/maven-public/org/springframework/spring-core/4.3.1.RELEASE/spring-core-4.3.1.RELEASE.pom
Downloaded from nexus maven: http://localhost:8081/repository/maven-public/org/springframework/spring-core/4.3.1.RELEASE/spring-core-4.3.1.RELEASE.pom (2.5 kB at 31 kB/s)
Downloading from nexus maven: http://localhost:8081/repository/maven-public/commons-logging/commons-logging/1.2/commons-logging-1.2.pom
.
.
.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 57.884 s
[INFO] Finished at: 2018-09-19T01:03:35+08:00
[INFO] ------------------------------------------------------------------------

发现plugin插件都是从阿里云镜像(代表中央仓库的优先级)下载的,而pom中的spring依赖包却是在阿里云镜像、jboss镜像中存在的情况下通过私服下载。因此,能得出结论,Maven中插件默认通过中央仓库进行下载,而其他依赖包下载时profile中的私服优先级大于中央仓库和pom中的其他远程仓库。

3、pom中其他远程仓库与中央仓库的优先级比较

在远程仓库中,除了镜像会覆盖拦截对应的远程仓库,远程仓库本身也有pom中定义的其他远程仓库和中央仓库,他们的优先级仍然需要进一步验证。

将settings.xml中的私服配置删除,保留中央镜像,内容如下:



  
  
  
  
    
      alimaven
      aliyun maven
      http://maven.aliyun.com/nexus/content/groups/public/
      central
    
  
  

pom中内容不变,运行指令"mvn clean install",结果的关键信息如下:

Downloading from jboss maven: http://repository.jboss.org/nexus/content/groups/public/org/springframework/spring-core/4.3.1.RELEASE/spring-core-4.3.1.RELEASE.pom
Downloaded from jboss maven: http://repository.jboss.org/nexus/content/groups/public/org/springframework/spring-core/4.3.1.RELEASE/spring-core-4.3.1.RELEASE.pom (2.5 kB at 926 B/s)
Downloading from jboss maven: http://repository.jboss.org/nexus/content/groups/public/commons-logging/commons-logging/1.2/commons-logging-1.2.pom
Downloading from alimaven: http://maven.aliyun.com/nexus/content/groups/public/commons-logging/commons-logging/1.2/commons-logging-1.2.pom
.
.
.
 ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.083 s
[INFO] Finished at: 2018-09-19T01:17:14+08:00
[INFO] ------------------------------------------------------------------------

可以看出优先从pom中定义的jboss仓库中下载,但因为网络问题,部分依赖包在jboss下载失败的情况下,去了阿里云中央镜像中下载。这说明,远程仓库中pom中的其他远程仓库优先级要高于中央仓库。

实际上这个优先级的本质为子pom优先级高于父pom,因为在Maven中默认的中央仓库定义在根pom中,所有的子pom继承自根pom,跟Java中的Object类类似。

可以进一步验证,同一个pom中的多个仓库,对每个依赖按照声明的顺序,然后结合网络连接情况,最终选择下载地址。

4、Maven的失败机制

可以继续通过如上的方法进行测试和验证,总结Maven的失败机制如下:         

  • Maven找不到包时,则会按照私服、pom中的远程仓库之后中央仓库的顺序逐层查找,最终仍然没有找到或者网络问题则报
  • 如果中途出现了重大异常,则采用快速失败机制
  • Maven包在Release版本和SNAPSHOT版本上的策略有一定的区别,主要是SNAPSHOT版本的依赖包多了时间戳比较的过程

5、总结

  • 使用mvn命令时候默认用的是全局settings.xml(少部分例外,如mac电脑上默认使用用户的settings.xml),而在IDEA中使用reimport时候用的是用户settings.xml;所以一般要求两个文件保持一致,也不推荐将IDEA配置改为全局settings.xml,因为升级会带来全局配置重置。
  • 依赖包下载时私服优先级高于pom中的远程仓库和中央仓库,插件下载默认使用中央仓库(或者其镜像)。
  • pom中的远程仓库优先级高于中央仓库,本质为子pom优先级高于父pom(默认的中央仓库定义在根pom中,所有的pom继承自根pom,与Java的Object类相似)。
  • 同一个pom中的多个远程仓库,对每个依赖包首先按照声明的顺序,然后根据网络连接情况,最终选择下载仓库。
  • Maven一般按照仓库优先级顺序下载依赖包,但如果中途报错(例如,依赖包编译有问题),则抛出异常,结束生命周期,即使之后的依赖包可能是可以正常下载和编译的。

最终给出仓库优先级部分的流程图如下所示: 

Maven仓库优先级以及失败机制分析_第2张图片

你可能感兴趣的:(Maven)