Виды репозиториев Maven: локальный, Maven Central и корпоративный
На ноутбуке разработчика модуль shop-web собирается без ошибок, а на CI-сервере та же команда mvn package падает с сообщением Could not find artifact com.examclouds:shop-core:jar:1.0-SNAPSHOT in central (https://repo.maven.apache.org/maven2). Код одинаковый, разница в репозиториях: shop-core когда-то установили командой mvn install в локальный репозиторий ~/.m2/repository ноутбука. На CI-сервере локальный репозиторий пуст, а в Maven Central такого артефакта нет. Ниже разберём, где Maven ищет артефакты и как сделать так, чтобы их видели все участники команды.
Репозиторий Maven (Maven repository) — это хранилище артефактов с фиксированной структурой каталогов, из которого Maven берёт зависимости и плагины и в которое публикует результаты сборки. Артефакт — файл, который адресуется координатами Maven: jar, war, pom-файл, архив исходников или Javadoc. Репозитории бывают двух видов: локальный (каталог ~/.m2/repository на вашем компьютере) и удалённые — центральный репозиторий Maven Central, корпоративные (Nexus, Artifactory) и сторонние. Нужный артефакт Maven сначала ищет в локальном репозитории и только потом скачивает из удалённых.
Что хранится в репозитории: артефакты и их адреса
Репозиторий артефактов Maven хранит файлы библиотек и проектов, разложенные по координатам groupId:artifactId:version. Путь к файлу вычисляется из координат: точки в groupId превращаются в каталоги, затем идут каталоги artifactId и версии, а имя файла строится как artifactId-version.расширение. Поэтому локальный, центральный и корпоративный репозитории устроены одинаково.
Например, библиотека с координатами com.google.code.gson:gson:2.11.0 лежит по адресу:
com/google/code/gson/gson/2.11.0/gson-2.11.0.jar
# local: ~/.m2/repository/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar
# central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar Как выбирать сами координаты, разобрано в разделах Координаты GAV и Как выбрать groupId, artifactId и version. В каталоге одной версии обычно лежит несколько файлов:
| Файл | Что это | Когда появляется |
|---|---|---|
gson-2.11.0.jar | Сам артефакт (для packaging = war — .war) | При первой сборке, которой нужна эта зависимость |
gson-2.11.0.pom | POM библиотеки: из него Maven узнаёт её собственные (транзитивные) зависимости | Всегда вместе с артефактом; у BOM и родительских POM есть только этот файл |
gson-2.11.0-sources.jar, gson-2.11.0-javadoc.jar | Исходники и документация (classifier sources и javadoc) | Только если их запросила IDE или команда, например mvn dependency:sources |
*.sha1 | Контрольные суммы для проверки целостности скачанного файла | Скачиваются из удалённого репозитория вместе с файлом |
_remote.repositories | Служебный файл: из какого репозитория (по id) получен артефакт | Создаёт Maven в локальном репозитории |
maven-metadata-*.xml | Метаданные: список версий, последняя сборка SNAPSHOT | Для SNAPSHOT-версий и при поиске версий плагинов |
Виды репозиториев Maven
В Maven есть локальный репозиторий и удалённые. Локальный — кэш на диске разработчика, в нём Maven ищет артефакты в первую очередь. Удалённые доступны по сети: это центральный репозиторий Maven Central (подключён по умолчанию), корпоративный репозиторий компании и сторонние публичные репозитории. Любой репозиторий, кроме локального, Maven считает удалённым.
| Репозиторий | Где находится | Кто наполняет | Когда используется |
|---|---|---|---|
| Локальный | ~/.m2/repository на компьютере разработчика или CI-сервера | Maven при скачивании; ваша команда mvn install | Всегда, в первую очередь |
| Центральный (Maven Central) | https://repo.maven.apache.org/maven2 | Авторы библиотек с открытым исходным кодом через Central Portal | По умолчанию, если артефакта нет в локальном |
| Корпоративный | Сервер компании: Nexus, Artifactory и аналоги | Команда разработчиков через mvn deploy; кэш Central | Если подключён в settings.xml или pom.xml |
| Сторонний публичный | Например, https://jitpack.io, репозитории вендоров | Владелец репозитория | Только если явно объявлен в <repositories> |
Локальный репозиторий ~/.m2/repository
Локальный репозиторий Maven по умолчанию находится в каталоге .m2/repository в домашней папке пользователя: ~/.m2/repository в Linux и macOS, C:\Users\<имя>\.m2\repository в Windows. Он персональный для каждого пользователя и общий для всех его проектов: библиотека, скачанная для одного проекта, повторно не скачивается для другого.
В локальный репозиторий артефакты попадают двумя путями: Maven скачивает их из удалённых репозиториев при сборке, а команда mvn install кладёт туда результат сборки вашего проекта — jar (или war, pom, в зависимости от значения packaging) вместе с его POM. После этого другие ваши проекты на этой машине могут подключить его как обычную зависимость. Фрагмент каталога после сборки проекта с Gson и mvn install проекта com.examclouds:shop:
~/.m2/repository/
├── com/
│ ├── examclouds/shop/1.0-SNAPSHOT/ # installed by mvn install
│ │ ├── shop-1.0-SNAPSHOT.jar
│ │ ├── shop-1.0-SNAPSHOT.pom
│ │ ├── maven-metadata-local.xml
│ │ └── _remote.repositories
│ └── google/code/gson/gson/2.11.0/ # downloaded from central
│ ├── gson-2.11.0.jar
│ ├── gson-2.11.0.jar.sha1
│ ├── gson-2.11.0.pom
│ ├── gson-2.11.0.pom.sha1
│ └── _remote.repositories
└── org/apache/maven/plugins/... # plugins are artifacts too Обратите внимание на последнюю строку: плагины Maven (maven-compiler-plugin, maven-surefire-plugin) — такие же артефакты, поэтому первая сборка даже пустого проекта скачивает десятки файлов. Сколько займёт каталог, зависит от проектов; на рабочей машине это часто несколько гигабайт. Удалять его безопасно: Maven скачает нужное заново, а установленные через mvn install собственные модули придётся установить повторно.
Как изменить путь. Постоянно — элементом <localRepository> в settings.xml, для одного запуска — системным свойством:
mvn package -Dmaven.repo.local=/tmp/m2-clean Отдельный пустой каталог удобен, чтобы проверить, соберётся ли проект «с нуля», как на CI-сервере: так ловится ситуация из начала урока.
Центральный репозиторий Maven Central
Maven Central — публичный репозиторий, который Maven использует по умолчанию: он объявлен во встроенном Super POM под id central с адресом https://repo.maven.apache.org/maven2. В нём опубликованы практически все Java-библиотеки и фреймворки с открытым исходным кодом, поэтому для большинства проектов настраивать репозитории не нужно.
Так центральный репозиторий объявлен в Super POM (его можно увидеть в выводе mvn help:effective-pom):
<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> Положить туда свой артефакт напрямую нельзя. Публикация идёт через Central Portal компании Sonatype, и при ней проверяется не код библиотеки, а формальные требования: право на namespace (groupId подтверждается владением доменом или аккаунтом, например io.github.username), наличие архивов исходников и Javadoc, подписи PGP и метаданные в POM (name, description, url, лицензия, разработчики, scm). Опубликованный релиз неизменен: его нельзя ни перезаписать, ни удалить, исправление выпускают новой версией. SNAPSHOT-версии в Maven Central не публикуются, поэтому в Super POM у central они отключены.
Поиск библиотек. Официальный поиск по Maven Central — central.sonatype.com (старый адрес search.maven.org). Популярный сайт mvnrepository.com — неофициальный каталог: он индексирует Central и некоторые другие репозитории, но сам артефакты Maven не раздаёт. Как правильно копировать оттуда координаты, описано в уроке Зависимости в Maven.
Центральный репозиторий работает только по HTTPS, а Maven начиная с версии 3.8.1 по умолчанию блокирует любые HTTP-репозитории — подробнее в уроке Что такое Maven.
Как Maven ищет зависимость
Для каждой зависимости и плагина Maven сначала проверяет локальный репозиторий. Если файл там есть (и это не SNAPSHOT, для которого подошло время проверки обновлений), он используется без обращения к сети. Иначе Maven по очереди опрашивает удалённые репозитории, пока один из них не вернёт артефакт, и сохраняет найденный файл в локальный репозиторий.
По документации Maven удалённые репозитории опрашиваются в таком порядке:
- репозитории из активных профилей
settings.xml(глобального, затем пользовательского); - репозитории из
pom.xmlпроекта, затем из родительских POM, и последним —centralиз Super POM; - репозитории, объявленные в POM-файлах зависимостей, по пути к нужному артефакту.
Если для репозитория настроено зеркало, запрос уходит на адрес зеркала. В логе сборки скачивание выглядит так:
[INFO] Downloading from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.11.0/gson-2.11.0.pom
[INFO] Downloaded from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.11.0/gson-2.11.0.pom (11 kB at 52 kB/s)
[INFO] Downloading from central: https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar Слово после from — id репозитория: по нему видно, откуда реально пришёл файл. Повторная сборка таких строк уже не выводит — всё берётся из ~/.m2/repository. SNAPSHOT-зависимости Maven перепроверяет в удалённом репозитории по расписанию updatePolicy (по умолчанию раз в сутки), подробнее — в разделе SNAPSHOT и релиз.
Неудача тоже кэшируется. Если артефакт не нашёлся (опечатка в версии, недоступный репозиторий), Maven записывает в локальный репозиторий служебный файл с отметкой о неудачной попытке (например, *.lastUpdated) и до истечения интервала обновлений в сеть за ним не идёт, даже если вы уже исправили настройки. Сообщение выглядит примерно так (формулировка зависит от версии Maven):
[ERROR] Failure to find com.example:report-lib:jar:1.0.0 in https://repo.maven.apache.org/maven2
was cached in the local repository, resolution will not be reattempted until the update interval
of central has elapsed or updates are forced Флаг mvn -U package заставляет Maven проверить удалённые репозитории заново. Если не помогло, удалите каталог этой версии в ~/.m2/repository.
Секция repositories в pom.xml
Чтобы Maven искал зависимости не только в Maven Central, в pom.xml добавляют секцию <repositories>: у каждого репозитория указываются уникальный id, адрес url и разрешение скачивать релизы и SNAPSHOT-версии. Для плагинов Maven используется отдельная секция <pluginRepositories> с теми же элементами.
<repositories>
<repository>
<id>company-public</id>
<url>https://nexus.example.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>company-public</id>
<url>https://nexus.example.com/repository/maven-public/</url>
</pluginRepository>
</pluginRepositories> Объявлять central в своём pom.xml не нужно: он и так приходит из Super POM. Значения updatePolicy: always, daily (по умолчанию), interval:N (минуты), never.
Указывать репозитории в pom.xml оправданно для открытого проекта, которому нужен сторонний публичный репозиторий: тогда проект соберётся у любого, кто его скачает. Внутри компании адрес корпоративного репозитория обычно задают не в каждом проекте, а один раз — зеркалом в settings.xml. Логины и пароли в pom.xml не пишут никогда: файл попадает в Git.
settings.xml: зеркала, логины и путь к репозиторию
settings.xml — файл настроек Maven на конкретной машине, а не в проекте: пользовательский ~/.m2/settings.xml и глобальный conf/settings.xml в каталоге установки Maven (при совпадении настроек побеждает пользовательский). В нём задают путь к локальному репозиторию, зеркала удалённых репозиториев, логины и пароли, прокси и профили с дополнительными репозиториями.
| Элемент | Что задаёт | Пример |
|---|---|---|
localRepository | Путь к локальному репозиторию | D:/maven/repository |
mirrors/mirror | Подменяет адрес одного или всех удалённых репозиториев (mirrorOf) | Все запросы — через корпоративный Nexus |
servers/server | Логин и пароль (или токен) для репозитория или зеркала с тем же id | Доступ к Nexus для скачивания и mvn deploy |
proxies/proxy | HTTP-прокси для выхода в интернет | Корпоративная сеть без прямого доступа |
profiles, activeProfiles | Дополнительные репозитории и свойства для всех проектов | Репозиторий SNAPSHOT-версий команды |
offline | Постоянный офлайн-режим (аналог флага -o) | true |
Типичный ~/.m2/settings.xml разработчика в компании: все запросы идут через корпоративный репозиторий, а учётные данные берутся из переменных окружения, чтобы пароль не лежал в файле открытым текстом:
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0">
<localRepository>D:/maven/repository</localRepository>
<mirrors>
<mirror>
<id>company-nexus</id>
<name>Company Nexus</name>
<url>https://nexus.example.com/repository/maven-public/</url>
<!-- all repositories, including central -->
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
<servers>
<server>
<!-- id must match the mirror or repository id -->
<id>company-nexus</id>
<username>${env.NEXUS_USER}</username>
<password>${env.NEXUS_PASSWORD}</password>
</server>
</servers>
</settings> Значения mirrorOf: * — все репозитории; central — только Maven Central; external:* — все, кроме локальных адресов (localhost, file://); список через запятую с исключениями, например *,!jitpack. Пароли в settings.xml можно также зашифровать командой mvn --encrypt-password (нужен мастер-пароль в ~/.m2/settings-security.xml). Какой файл настроек реально применился, показывает mvn help:effective-settings.
Неочевидный момент: mirrorOf * перехватывает и ваши repositories
Зеркало с <mirrorOf>*</mirrorOf> подменяет адрес любого репозитория, в том числе объявленного в <repositories> проекта. Вы добавляете в pom.xml https://jitpack.io, а Maven всё равно ищет артефакт в корпоративном Nexus и сообщает Could not find artifact ... in company-nexus: в логе вместо id вашего репозитория стоит id зеркала. Решение — добавить JitPack как proxy-репозиторий в Nexus или исключить его из зеркала: <mirrorOf>*,!jitpack</mirrorOf>, где jitpack — id репозитория в pom.xml.
Корпоративный репозиторий: Nexus и Artifactory
Корпоративный репозиторий — удалённый репозиторий, который компания разворачивает на своём сервере, чтобы хранить собственные артефакты и кэшировать публичные. Содержимое и доступ к нему вы полностью контролируете, как в локальном репозитории, но он общий для всей команды и CI-серверов. Самые распространённые решения — Sonatype Nexus Repository и JFrog Artifactory; Maven-репозитории также предоставляют GitHub Packages, GitLab Package Registry и облачные сервисы.
Внутри такого сервера обычно настраивают репозитории трёх типов (названия — как в Nexus, в Artifactory аналогично: local, remote, virtual):
| Тип | Что делает | Пример в Nexus |
|---|---|---|
| hosted | Хранит артефакты, опубликованные командой через mvn deploy | maven-releases, maven-snapshots |
| proxy | Кэширует удалённый репозиторий: первый запрос скачивает файл из Central, следующие отдаются с сервера компании | maven-central |
| group | Объединяет несколько репозиториев под одним адресом — именно его прописывают в зеркале | maven-public |
Что даёт корпоративный репозиторий:
- Обмен внутренними библиотеками. Модуль
shop-coreиз начала урока публикуется командойmvn deployи становится доступен всем разработчикам и CI-серверу. - Закрытость кода. Доступ ограничивается учётными записями и правами на сервере, артефакты не выходят за пределы компании.
- Скорость и устойчивость. Библиотеки из Central скачиваются из сети компании один раз, сборки не зависят от доступности интернета и внешних серверов.
- Контроль. Можно запретить скачивание библиотек с известными уязвимостями или неподходящими лицензиями (функции зависят от продукта и редакции).
Разработчику для подключения обычно достаточно настроить зеркало и server в settings.xml, как в примере выше, а для публикации — добавить в проект <distributionManagement>.
mvn install и mvn deploy: куда попадает артефакт
Команда mvn install собирает проект и копирует артефакт с его POM в локальный репозиторий — он становится доступен только другим проектам на этом компьютере. Команда mvn deploy выполняет то же самое и дополнительно загружает артефакт в удалённый репозиторий из <distributionManagement>, откуда его получат коллеги и CI-серверы.
| Признак | mvn install | mvn deploy |
|---|---|---|
| Куда попадает артефакт | ~/.m2/repository текущего пользователя | Локальный репозиторий и удалённый (корпоративный) |
| Кто увидит | Только проекты на этой машине | Все, у кого есть доступ к удалённому репозиторию |
| Что нужно настроить | Ничего | <distributionManagement> в pom.xml и server с тем же id в settings.xml |
| Имя SNAPSHOT-файла | shop-1.0-SNAPSHOT.jar | С меткой времени: shop-1.0-20261107.101530-1.jar |
| Кто обычно запускает | Разработчик | CI-сервер после успешной сборки |
Куда публиковать, задаётся отдельно для релизов и SNAPSHOT-версий; Maven выбирает репозиторий по суффиксу версии проекта:
<distributionManagement>
<repository>
<id>company-releases</id>
<url>https://nexus.example.com/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>company-snapshots</id>
<url>https://nexus.example.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement> mvn deploy
# Output (fragment):
[INFO] Uploading to company-snapshots: https://nexus.example.com/repository/maven-snapshots/com/examclouds/shop/1.0-SNAPSHOT/shop-1.0-20261107.101530-1.jar
[INFO] Uploaded to company-snapshots: https://nexus.example.com/repository/maven-snapshots/com/examclouds/shop/1.0-SNAPSHOT/shop-1.0-20261107.101530-1.jar (12 kB at 40 kB/s)
[INFO] BUILD SUCCESS Для логина Maven ищет в settings.xml элемент <server> с id company-snapshots (или company-releases для релиза). Что выводит mvn install и в каком порядке выполняются фазы до install и deploy, описано в уроках Как установить Maven и Жизненный цикл сборки Maven.
Нюанс: файла 1.0-SNAPSHOT.jar в удалённом репозитории нет
При mvn deploy SNAPSHOT-версия сохраняется с меткой времени и номером сборки: shop-1.0-20261107.101530-1.jar, следующий deploy даст ...-2.jar. Какая сборка последняя, Maven узнаёт из maven-metadata.xml в каталоге версии. Поэтому скрипт, который скачивает .../1.0-SNAPSHOT/shop-1.0-SNAPSHOT.jar по прямой ссылке, получит 404, хотя в зависимостях 1.0-SNAPSHOT работает. Релизная версия (1.0.0) хранится под своим обычным именем.
Частые ошибки при работе с репозиториями
Большинство проблем с репозиториями Maven сводится к трём причинам: артефакт есть только в чьём-то локальном репозитории, Maven обращается не к тому репозиторию (из-за зеркала или кэша неудачи) или у него нет прав на доступ. Текст ошибки обычно содержит id репозитория — с него и начинайте диагностику.
| Что видите | Причина | Как исправить |
|---|---|---|
Could not find artifact com.examclouds:shop-core:jar:1.0-SNAPSHOT in central на CI или у коллеги | Модуль установлен через mvn install только в ваш локальный репозиторий | Опубликовать его в корпоративный репозиторий (mvn deploy) или собирать модули вместе в одном многомодульном проекте |
... was cached in the local repository, resolution will not be reattempted ... | Неудачная попытка скачивания закэширована | mvn -U; при необходимости удалить каталог версии в ~/.m2/repository |
status code: 401, reason phrase: Unauthorized (401) | Нет <server> или его id не совпадает с id зеркала/репозитория | Сделать id одинаковыми, проверить логин и токен через mvn help:effective-settings |
Blocked mirror for repositories: [... (http://...)] | Репозиторий указан по HTTP, а Maven 3.8.1+ блокирует HTTP | Перевести адрес на HTTPS (корпоративный сервер — настроить на нём HTTPS) |
Репозиторий из pom.xml «не работает», в логе другой id | Зеркало с mirrorOf = * перехватывает все запросы | Исключить репозиторий в mirrorOf или добавить его в Nexus как proxy |
Повторный mvn deploy релиза завершается ошибкой 400 | Hosted-репозиторий релизов по умолчанию запрещает перезапись | Поднять версию (1.0.1); перезаписывать можно только SNAPSHOT |
| Свежие изменения SNAPSHOT-зависимости не подтягиваются | Не наступило время проверки по updatePolicy (по умолчанию — раз в сутки) | mvn -U package |
Часто задаваемые вопросы
Чем mvnrepository.com отличается от Maven Central?
Maven Central (https://repo.maven.apache.org/maven2) — сам репозиторий, из которого Maven скачивает файлы. mvnrepository.com — неофициальный сайт-каталог: на нём удобно искать библиотеки и копировать фрагмент <dependency>, но указывать его адрес в <repositories> бессмысленно — это не Maven-репозиторий. Официальный поиск по Central — central.sonatype.com.
Как добавить в локальный репозиторий jar, которого нет в Maven Central?
Командой mvn install:install-file -Dfile=lib/legacy-sdk.jar -DgroupId=com.vendor -DartifactId=legacy-sdk -Dversion=2.3 -Dpackaging=jar. После этого jar подключается в pom.xml как обычная зависимость с этими координатами. Но он будет только на вашей машине, поэтому в команде такой файл публикуют в корпоративный репозиторий командой mvn deploy:deploy-file с параметрами -Durl и -DrepositoryId.
Как перенести локальный репозиторий Maven на другой диск?
Укажите новый путь в элементе <localRepository> файла ~/.m2/settings.xml (в Windows — C:\Users\<имя>\.m2\settings.xml; если файла нет, создайте его), например D:/maven/repository. Старый каталог можно перенести туда же или удалить — Maven скачает зависимости заново. В IntelliJ IDEA проверьте, что в настройках Maven используется тот же settings.xml. Пример файла — в разделе settings.xml.
Чем Nexus отличается от Artifactory?
Для Maven оба решают одну задачу: хранят собственные артефакты команды (hosted/local), кэшируют Maven Central (proxy/remote) и объединяют репозитории под одним адресом (group/virtual). Оба поддерживают и другие форматы (npm, Docker, PyPI), у обоих есть бесплатная и коммерческие редакции. Выбор обычно определяется инфраструктурой компании; настройка Maven для них одинакова — зеркало и server в settings.xml.
Можно ли работать с несколькими удалёнными репозиториями одновременно?
Да. Maven опрашивает их по очереди, пока один не вернёт артефакт: сначала репозитории из профилей settings.xml, затем из pom.xml и родителей, последним — Maven Central. Каждый лишний репозиторий замедляет поиск отсутствующих артефактов, поэтому в компаниях их объединяют в один group-репозиторий на Nexus или Artifactory. Подробнее — в разделе Как Maven ищет зависимость.
Practice
Reinforce this lesson with hands-on tasks, each with a level and a time estimate.
All module tasks →
Comments