依赖找不到?尊嘟假嘟?还不是仓库没配好

Maven仓库

在 Maven 的术语中,仓库是一个位置(place)。Maven 仓库是项目中依赖的第三方库,这个库所在的位置叫做仓库。

在 Maven 中,任何一个依赖、插件或者项目构建的输出,都可以称之为构件。Maven 仓库能帮助我们管理构件(主要是 JAR),它就是放置所有 JAR 文件(WAR,ZIP,POM 等等)的地方。

1. 仓库分类

对于 Maven 来说,仓库种类可以分为两种,一种是本地仓库 ,另一种是远程仓库。而在远程仓库当中,又可以分为中央仓库,私服和其他的公共仓库。

仓库类型 存储位置 作用 访问优先级
本地仓库 用户目录下的.m2/repository 缓存远程下载的依赖 1
远程仓库 网络服务器 提供依赖和插件的集中存储 2
- 中央仓库 repo.maven.apache.org Maven官方维护的默认仓库 2.1
- 私服仓库 公司内部搭建(如Nexus) 托管私有依赖,加速构建 2.2
- 其他公共仓库 如阿里云、JCenter等 镜像或补充中央仓库 2.3

1.1 本地仓库

Maven 所需要的任何构件都是直接从本地仓库获取的。如果本地仓库没有,它会首先尝试从远程仓库下载构件至本地仓库,然后再使用本地仓库的构件。

本地仓库默认在用户目录下的.m2/repository,可以在maven配置文件settings.xml中的localRepository属性修改位置,如下修改为D:/maven/repository:

xml 复制代码
<settings>
	  ...
      <localRepository>D:/maven/repository</localRepository>
      ...
</settings>

1.2 远程仓库

好比藏书,本地仓库就是自己的书房,远程仓库就是书店。如果你想看一本《西游记》,在自己书房没有找到,那就可以去书店买一本回来放在自己书房。然后你又想看一本新出的《xxx》,附件书店没有但是网上有卖,这时你可以从网上买来放自己书房。

相应的,maven需要构件时如果本地仓库找不到就会去远程仓库寻找并下载到本地仓库。一般来说,一个人只有一个书房,但是外面可以买书的地方很多,对应到maven就是,本地仓库只有一个,但是远程仓库可以有多个。

1.2.1 中央仓库

Maven 中央仓库是由 Maven 社区提供的仓库,由 Maven 社区来维护的,里面存放了绝大多数开源软件的包,并且是作为 Maven 的默认配置,不需要开发者额外配置。

中央仓库的关键概念:

  • 这个仓库由 Maven 社区管理。
  • 不需要配置
  • 需要连接外部网络才能访问。

中央仓库默认在超级POM(项目的pom.xml会继承这个超级POM)中已经配置,默认访问地址:repo.maven.apache.org/maven2

xml 复制代码
<repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
</repositories>
1.2.2 其他远程仓库

有了中央仓库,为什么还需要其他的远程仓库呢?

  • 我们要找的构件可能不存在于中央仓库中;
  • 由于某些原因,访问中央仓库的速度相对较慢。

这种时候,我们就可以选择一个使用起来相对方便的远程仓库来配置。

比如国内常用的阿里云maven仓库:maven.aliyun.com/nexus/conte...

1.2.3 私服

私服也是属于远程仓库的一种,相对公共仓库而言属于某个公司或者某个开发团队私有的远程仓库。通常部署在某个局域网内,提供局域网的内部用户使用。当maven需要下载构件时,它从私服请求,如果私服上不存在该构件,则从外部远程仓库下载并缓存到私服上,后续下载将直接从私服下载。此外,一些无法在外部仓库下载的构件也可以上传到私服(通常是一些公司内部构件),供本地开发人员使用。

私服的好处:

  • 更快的下载速度:由于是局域网内部的请求,因此下载构件的速度是可以保证的;
  • 更稳定的构建:如果我们依赖某个外部的远程仓库,当这个仓库出现不可能用的情况,哪怕是网络的波动,都有可能会造成我们的构建失败;
  • 部署第三方构件:部署公司私有的、不公开的构件。如果一个公司使用了微服务架构,那么公共仓库是肯定没办法获取这些私有的构件的。

1.2 依赖搜索顺序

Maven 按照以下顺序查找依赖的库:

  • 步骤 1 - 在本地仓库中搜索,如果找不到,执行步骤 2,如果找到了则执行其他操作。
  • 步骤 2 - 在中央仓库中搜索,如果找不到,并且有一个或多个远程仓库已经设置,则执行步骤 4,如果找到了则下载到本地仓库中以备将来引用。
  • 步骤 3 - 如果远程仓库没有被设置,Maven 将简单的抛出错误(无法找到依赖的文件)。
  • 步骤 4 - 在一个或多个远程仓库中搜索依赖的文件,如果找到则下载到本地仓库以备将来引用,否则 Maven 将停止处理并抛出错误(无法找到依赖的文件)。Maven查询远程仓库时会合并所有配置源 ,形成一个"有效仓库列表",并按照配置的先后顺序进行查找。

2. 远程仓库配置

2.1 repository

可以在项目的pom.xml使用<repository>标签自定义远程仓库:

xml 复制代码
<repositories>
    <repository>
        <id>aliyun</id>
        <name>Aliyun Maven</name>
        <url>https://maven.aliyun.com/repository/public</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled> <!-- 禁用SNAPSHOT版本 -->
        </snapshots>
    </repository>
</repositories>

<repositories>中可以配置多个仓库<repository>,任何一个仓库的<id>必须是唯一 的,需要注意中央仓库的<id>默认是central,如果你配置的仓库<id>使用了central,那么将会覆盖中央仓库的配置;<url>指向远程仓库的访问地址;<release>snapshot>表示对构建版本下载的控制,SNAPSHOTS快照后面会详细介绍。

2.1.1 认证

有些远程仓库是需要账号密码认证的,比如nexus私服一般就会配置认证。

因为项目的pom.xml配置文件一般会提交到代码库,为避免泄露隐私,所以maven配置仓库认证的地方在本地maven的配置文件settigns.xml中。具体在<servers>标签下配置一个<server>,其中<id>必须跟需要认证的仓库<repository><id>保持一致。

xml 复制代码
<servers>
    <server>
        <id>aliyun</id> <!-- 假设aliyun仓库需要认证 -->
        <username>admin</username>
        <password>admin</password>
    </server>
</servers>

2.2 mirror

如果仓库X可以提供仓库Y的所有构件,那么X可以认为是Y的镜像仓库,比如说aliyun的仓库就是中央仓库的镜像仓库。由于网络问题,国内使用一般会使用镜像仓库代理对中央仓库的访问,提示访问稳定性,降少对中央仓库的压力。

镜像在maven配置文件settigns.xml中的<mirrors>标签中配置:

xml 复制代码
<mirrors>
    <mirror>
        <id>aliyun</id>
        <name>Aliyun Mirror</name>
        <url>https://maven.aliyun.com/repository/public</url>
        <mirrorOf>central</mirrorOf> <!-- 镜像中央仓库 -->
    </mirror>
</mirrors>

镜像镜像配置最重要的值就是<mirrorOf>,其他值跟<repository>并无二异。<mirrorOf>的值表示被镜像仓库的<id>,比如上面的配置表示所有对central仓库的访问都将被替换成访问该aliyun仓库。

<mirrorOf>的更多配置值:

  • <mirrorOf>*</mirrorOf>,使用*号匹配所有仓库,对任何仓库的访问都将被替换成访问镜像仓库
  • <mirrorOf>repo1,repo2</mirrorOf>,使用,逗号分隔多个远程仓库。
  • <mirrorOf>*, !repo1</mirrorOf>,匹配所有远程仓库,但是使用!repo1排除

注意,对原仓库的访问会被完全替换成访问镜像仓库,如果原仓库无法访问或者没有构件同样会报错。

镜像仓库通常结合私服使用。由于私服可以代理任何外部远程仓库,因此,对于内部用户来说,配置一个私服地址就等于使用了所有需要的外部从仓库,从而简化maven的配置。如下配置了刚刚搭建的nexus私服:

xml 复制代码
<mirrors>
    <mirror>
        <id>internal-mvnrepository</id>
        <name>Aliyun Mirror</name>
        <url>http://localhost:8081/repository/maven-public/</url>
        <mirrorOf>*</mirrorOf>
    </mirror>
</mirrors>

上面的配置将对所有远程仓库的访问都替换成访问internal-mvnrepository私服仓库,只需要在私服仓库配置对其他需要的远程仓库。后文将详细描述nexus私服的使用和配置。

2.2.1 认证

如果镜像仓库也需要认证,跟之前一样,配置一个<server><id>对应mirror的<id>即可。

2.3 插件仓库

与依赖构件一样,插件构件同样基于坐标存储在Maven仓库中。在需要的时候,Maven会从本地仓库寻找插件,如果不存在,则从远程仓库查找。找到插件之后,再下载到本地仓库使用。 需要特别注意的是 ,Maven会区别对待依赖的远程仓库与插件的远程仓库,之前介绍了远程仓库的配置,但那种配置只对一般依赖有效 果。当Maven需要的依赖在本地仓库不存在时,它会去所配置的远程仓库查找,可是当Maven需要的插件在本地仓库不存在 时,它不会去这些配置的远程仓库查找。但是会去超级POM配置的默认插件仓库查找,Maven内置了如下的插件远程仓库配置:

xml 复制代码
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url> <!-- 中央插件仓库 -->
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </pluginRepository>
  </pluginRepositories>

不同于repositories及其repository子元素,要想让给插件配置远程仓库,需要使用pluginRepositories和pluginRepository配置。

如果官方提供的插件仓库无法满足需求,同样可以额外配置远程插件仓库。

3. 快照(SNAPSHOT)

可以说大部分人都不清楚SNAPSHOT在maven中的作用

xml 复制代码
<groupId>org.example</groupId>
<artifactId>day04-springboot</artifactId>
<version>1.0-SNAPSHOT</version> <!-- 快照版本 -->

一个大型的软件应用通常包含多个模块,并且通常的场景是多个团队开发同一应用的不同模块。举个例子,设想一个团队开发应用的项目为 app-ui(app-ui.jar:1.0),而另一个团队使用的项目是 data-service(data-service.jar:1.0)。

现在可能出现的情况是开发 data-service 的团队正在进行快节奏的 bug 修复或者项目改进,并且他们几乎每隔一天就要发布库到远程仓库。 现在如果 data-service 团队每隔一天上传一个新版本,那么将会出现下面的问题:

  • data-service 团队每次发布更新的代码时都要告知 app-ui 团队。
  • app-ui 团队需要经常地更新他们 pom.xml 文件到最新版本。

为了解决这种情况,快照的概念派上了用场。

快照是一种特殊的版本,版本值带有后缀:-SNAPSHOT,指定了某个当前的开发进度的副本。不同于常规的版本,Maven 每次构建都会在远程仓库中检查新的快照。

对于非快照版本,如果 Maven 以前下载过指定的版本文件,比如说 data-service:1.0,Maven 将不会再从仓库下载新的可用的 1.0 文件。若要下载更新的代码,data-service 的版本需要升到1.1。快照的情况下,每次 app-ui 团队构建他们的项目时,Maven 将自动获取最新的快照(data-service:1.0-SNAPSHOT)。

快照版本实现依赖时间戳,就是每次构件部署时给构件添加一个时间戳。maven发现依赖的说snapshot版本构件时,即使版本没有变化也会每次从所有远程仓库中检索构件的版本信息,然后对比本地仓库的版本信息,得到最新时间戳版本的构件,并使用它。

4. nexus私服

Sonatpe Nexus Repository 通常被称作为Nexus , 是由 Sonatype 出品的目前世界上最流行仓库管理软件,不仅仅可以作为maven的私服,还可以作为pip、npm、docker等的构件仓库。

4.1 安装nexus

使用docker compose快速安装nexus:

yaml 复制代码
services:
    nexus:
        container_name: nexus
        environment:
            - TZ=Asia/Shanghai
        image: sonatype/nexus3:3.87.1
        ports:
            - 8081:8081
        restart: always
        volumes:
            - ./data:/nexus-data

访问端口映射到8081,数据存储在./data

访问nexus地址http://localhost:8081:

可以看到nexus 默认创建了四个maven相关仓库,点击url的copy按钮即可复制对应仓库的地址。比如maven-central: http://localhost:8081/repository/maven-central/

4.1.1 默认仓库说明
仓库名称 说明
maven-central Nexus 对 Maven 中央仓库的代理
maven-public Nexus 默认创建,供开发人员下载使用的组仓库
maven-releasse Nexus 默认创建,供开发人员部署自己 jar 包的宿主仓库,要求 releasse 版本
maven-snapshots Nexus 默认创建,供开发人员部署自己 jar 包的宿主仓库,要求 snapshots 版本

4.2 nexus仓库类型

在nexus创建仓库有下面三个选项:

它们的用途如下:

仓库类型 用途
hosted 存放私有构件
proxy 代理远程仓库
group 聚合多个仓库
4.2.1 hosted

nexus宿主仓库,该仓库的主要配置项就是Version policy,用于控制能够上传至该仓库构件是Release还是Snapshot,或者是混合两种版本。hosted仓库的主要作用就是存放私有的构件,比如公司内部的公共构件就会上传在这里,使用maven deploy也会将Jar包上传至该类型仓库。该仓库不会访问外部仓库,也不会从外部仓库下载构件。

4.2.2 proxy

这个仓库就是一个远程仓库代理,如果访问私服仓库没有找到构件将会从代理的远程仓库查找构件,如果成功下载到构件,将会缓存在nexus的proxy仓库中,下次访问私服将从proxy仓库下载构件。

创建proxy仓库页面如下:主要配置就是仓库名称name,版本策略version policy和远程仓库地址remmote storage

默认仓库maven-central就是proxy仓库,它配置了一个namemaven-centrlversion policyReleaseRemote storagehttps://repo1.maven.org/maven2/的仓库。

下图是我配置nexus私服后,maven项目下载完依赖后maven-central仓库的内容,已经将本地仓库没有的依赖下载到了maven-central仓库。

4.2.3 group

group不是物理概念上的仓库,而是逻辑仓库,它的作用就是将多个nexus仓库组合起来。maven访问group仓库就等于可以访问group组内的所有仓库。

下图是nexus默认仓库maven-public的部分配置,表示将maven-releases、maven-snapshots、maven-central设置为group仓库的成员。所以maven中只需要配置nexus的maven-public仓库就相当于配置了三个仓库。

5. 部署至私服

mvn install会将构件放入本地仓库,mvn deploy同时将构件放入本地仓库和配置的远程仓库。

5.1 手动上传

可以手动将打包后的jar通过nexus的web页面上传。

5.2 maven deploy

想要使用maven deploy将构件部署到仓库,需要在pom.xml中使用<distributionManagement>标签指定部署的仓库

xml 复制代码
<distributionManagement>
    <repository>
        <id>oect-repo</id>
        <name>public maven proxy</name>
        <url>http://localhost:8081/repository/maven-releases/</url>
    </repository>
    <snapshotRepository>
        <id>oect-repo</id>
        <name>public maven proxy</name>
        <url>http://localhost:8081/repository/maven-snapshots/</url>
    </snapshotRepository>
</distributionManagement>

<repository>配置的是Release版本构件的仓库,<snapshotRepository>配置的是Snapshot版本构件的仓库。

如果pom中配置的versionRelease版本,当版本号不改动时,多次执行mvn deploy构件只有第一次会被部署到Release仓库。后续执行的mvn deploy会报错,Snapshot是多次部署不会报错,查看Snapshot仓库可以看到多个带时间戳的构件版本。

实际上仓库有一个配置项deployment policy,默认是Disable redeploy,不允许release重新部署同一个版本,可以修改成allow redeploy,允许release版本重新部署同一个版本。不建议更改成allow redeploy,release表示稳定版本,不应该进行修改。

6. 总结

Maven仓库作为构件(JAR、WAR等)的存储中心,是Maven实现依赖管理和自动化构建的基石。其核心可以概括为以下几点:

  1. 清晰的仓库层级与协作机制 :Maven采用"本地仓库"与"远程仓库"协同工作的模式。本地仓库作为缓存,避免了重复下载;而远程仓库(包括中央仓库、其他公共仓库和私服)则是构件的最终来源。Maven严格的依赖搜索顺序确保了构建的效率和稳定性。
  2. 插件与依赖仓库的差异性:这是容易"踩坑"的地方。Maven会区别对待依赖仓库和插件仓库。如果插件不在本地仓库,需要确保其所在的远程仓库(如中央仓库)被正确镜像或代理,否则会导致插件下载失败。
  3. 镜像与私服的强大威力 :使用镜像(如阿里云Maven镜像)可以显著提升在国内网络环境下下载构件的速度。而搭建Nexus等私服,则更进一步,它不仅作为内部构件的唯一发布中心 ,还能代理和缓存所有外部公共仓库 。通过配置一个覆盖所有仓库(<mirrorOf>*</mirrorOf>)的私服镜像,可以简化项目配置,提升构建速度,并增强公司内部开发的稳定性和安全性。
  4. SNAPSHOT版本的动态更新特性 :快照版本(-SNAPSHOT)是为模块间频繁联调而设计的机制。Maven会自动检查并获取远程仓库中快照构件的最新版本,这极大地便利了并行开发。但同时也需要注意,在发布生产环境时,必须确保使用稳定的Release版本。
  5. Nexus私服的精细化仓库管理:Nexus通过三种仓库类型(Hosted, Proxy, Group)实现了精细化的管理。理解并正确配置这些仓库是高效使用私服的关键。特别是Group仓库,它将多个物理仓库聚合为一个统一的访问入口,极大地简化了客户端的配置。
相关推荐
_半夏曲1 天前
maven多依赖,由于包路径一样,导致引入类错乱
java·maven
Edward111111111 天前
普通java项目转为maven项目 J文件后缀.java变C文件
java·开发语言·maven
考虑考虑1 天前
maven项目使用指定JDK版本打包
java·后端·maven
Su-RE1 天前
springboo打包--Maven 打包
java·maven
running up2 天前
Maven依赖管理和项目构建工具
java·maven
mike04122 天前
Eclipse+maven+selenium自动化测试开发环境搭建
selenium·eclipse·maven
Li_7695322 天前
IDEA 中 maven 图标失踪解决措施
java·maven·intellij-idea
mike04122 天前
Eclipse配置Maven详细教程(实测)
java·eclipse·maven