Структура и сборки Java-проектов
Структуры проекта
Что такое пакет?
Пакетом (пространством имен) в Java называется структура вложенных по какому-то признаку папок с размещенными в них классами (интерфейсами, перечислениями, аннотациями), необходимыми проекту.
В Java используется пакетная структура – способ организации классов в папках, который помогает избежать конфликтов имён и группировать код логически. Это обязательная структура. Чтобы система понимала, что означает команда, указанная программистом в исходном коде в виде слова, нужно сообщить системе об использовании пакета, который содержит код-содержание этого слова:
"Дружище, налей мне молока!"
"А где мне взять молоко?".
Мы, люди, многие элементарные вещи уже изначально автоматизировали в себе и понимаем подсознательно. Мы прекрасно знаем, что молоко в холодильнике. Но программе нужно показать, что нам понадобится холодильник. Поэтому общение с программой будет как-то так:
"Дружище, запомни – вот холодильник. Там есть молоко".
"Дружище, налей мне молока!"
"Ок, вижу, молоко в холодильнике. Сейчас сделаю".
Вот поэтому код библиотеки или проекта формируется в составе пакета (package).
Практический эффект чувствуется сразу — как только проект перестаёт быть "одним файлом", правильная пакетная структура экономит часы на навигации, поиске и согласовании изменений в команде.
Пакетная структура решает две задачи: предотвращает конфликты имён между классами из разных источников и группирует связанный код для удобства навигации и поддержки.
Play ITЗагрузка интерактивного демо…
Пакет — это механизм организации классов и интерфейсов в пространстве имен (namespace), который позволяет структурировать код, предотвращать конфликты имен и управлять доступом к компонентам программы. В Java пакеты соответствуют структуре директорий на диске.
Структура пакетов
Каждый Java-файл начинается с директивы package, указывающей полный путь к пакету.
package com.example.myapp.utils;
Компилятор использует этот путь для размещения скомпилированных .class файлов в соответствующих подкаталогах. Без указания пакета класс попадает в безымянное пространство имён, что допустимо только для простых учебных программ.
Физическая структура каталогов соответствует логическому имени пакета. Для класса с объявлением package com.example.app; компилятор ожидает размещение исходного файла по пути com/example/app/ClassName.java. Обратный слеш в имени пакета заменяется на разделитель каталогов операционной системы.
Имена пакетов строятся по обратному порядку домена организации, и хранятся в строгой структуре:
- com/mycompany/project/Main.java – физический путь;
- com.mycompany.project – путь в коде.
com – корень пакета. Только строчные буквы. Это префикс домена, обычно обратный интернет-домен компании или проекта. Нужен для уникальности пакетов в мире. Можно указывать своё, но рекомендуется использовать стандарт:
- com – для коммерческих проектов;
- org – для открытых проектов;
- net, io, ru – тоже допустимы.
mycompany – название компании или автора, допустим, имя (если проект личный). Желательно делать уникальным. Только строчные буквы, несмотря на то что это будет имя или название – допустим, не Timur, а timur.
project – название проекта или модуля, библиотеки, подсистемы. Допустим, calculator, utils или как-то так. Только строчные буквы, название может быть любым.
Такой подход гарантирует глобальную уникальность имён пакетов. Два разработчика из разных компаний могут создать класс User, но их полные имена com.companyA.app.User и org.companyB.tool.User никогда не пересекутся.
Система сборки в Java
Современные Java-проекты используют системы сборки Maven и Gradle. Это инструменты, которые автоматизируют компиляцию кода, управление зависимостями (библиотеками), запуск тестов, создание готовых приложений и развёртывание (деплой).
По сути, сборка — это повторяемый сценарий "собери одинаково у каждого разработчика и на CI". Именно повторяемость отличает инженерный процесс от ручных запусков команд.
Система сборки в Java представляет собой автоматизированный процесс преобразования исходного кода и ресурсов в исполняемый продукт, готовый к запуску или распространению. Этот процесс объединяет компиляцию файлов, проверку зависимостей, управление версиями и упаковку результатов в единый формат.
В экосистеме Java стандартом де-факто для управления сборкой является инструмент Maven. Он работает на основе декларативного подхода: разработчик описывает проект и его потребности в файле конфигурации pom.xml, а система сама выполняет необходимые шаги для получения результата.
Процесс сборки в Java проходит через несколько четко определенных стадий, которые выполняются последовательно. Каждая стадия отвечает за свою часть работы: от очистки старых файлов до финальной упаковки. Понимание этих этапов помогает эффективно диагностировать ошибки и оптимизировать работу.
-
Очистка (Clean) — удаляет
target/(см.mvn cleanв блоке CLI ниже). -
Сборка (Compile). На этой стадии компилятор Java обрабатывает исходные файлы
.java, расположенные в папкеsrc/main/java. Инструмент проверяет правильность синтаксиса, соответствие типов данных и наличие всех объявленных классов и методов. Если ошибок нет, генерируются файлы.classв папкеtarget/classes. Эти файлы содержат байт-код, который является платформенно-независимым представлением программы. Компиляция также включает обработку аннотаций и генерацию вспомогательных файлов, если они требуются фреймворками. -
Тестирование (Test). Система копирует скомпилированные классы в специальную директорию
target/test-classesи запускает набор тестов, находящихся в папкеsrc/test/java. Тесты проверяют логику работы отдельных методов и классов. Если хотя бы один тест падает, сборка останавливается, и процесс завершается ошибкой. Это предотвращает выпуск продуктов с известными дефектами. Результаты тестирования сохраняются в виде отчетов в формате XML или HTML, которые можно проанализировать позже. -
Упаковка (Package). Скомпилированный код и ресурсы объединяются в архивный файл. Для стандартных приложений это JAR-файл (Java ARchive), содержащий классы и метаданные. Для веб-приложений создается WAR-файл (Web ARchive), включающий HTML, CSS, JavaScript и конфигурационные файлы. Упакованный артефакт становится готовым к развертыванию продуктом. В процессе упаковки также может происходить проверка целостности файлов и их подписывание цифровыми сертификатами.
-
Установка (Install). Результат предыдущей стадии помещается в локальный репозиторий пользователя. Обычно это папка
.m2/repositoryв домашней директории операционной системы. Установка делает библиотеку доступной для других проектов, работающих на этом компьютере. Если другой проект ссылается на эту библиотеку по групповому идентификатору, имени и версии, он найдет её в локальном хранилище без необходимости скачивания из сети. -
Развертывание (Deploy). Этот шаг выполняется только по требованию и подразумевает перемещение собранного артефакта в удаленный репозиторий. Развертывание позволяет команде разработчиков получить доступ к последней версии библиотеки через сеть. Удаленные репозитории часто используются внутри компаний для хранения внутренних инструментов или публикуются в интернете для широкого доступа.
Зависимости
Зависимости в Java — это внешние библиотеки, которые расширяют функциональность приложения. Они могут включать готовые реализации алгоритмов, инструменты для работы с сетью, базы данных или графическими интерфейсами.
В Java нет встроенной системы зависимостей (как в Go или Rust). Вместо этого есть инструменты сборки (Maven, Gradle), которые опираются на соглашения. Принцип координат в Maven (Maven Coordinates) определяет, что каждая зависимость имеет три значения:
groupId:artifactId:version
К примеру:
org.springframework:spring-core:5.3.27
Внутри это работает так:
pom.xmlдекларирует всё, что нужно проекту.- Репозиторий - это хранилище JAR-файлов (обычно Maven Central или частный Nexus/Artifactory).
- Локальный кэш (~/.m2/repository) хранит скачанные один раз JAR-файлы, на диске.
- Если
Aзависит отB, аBотC, то Maven сам скачает иC, и разрешит конфликты версий по стратегии "ближайший к корню". Это транзитивные зависимости.
То есть, зависимости не устанавливаются в систему, а привязываются к конкретному проекту.
Система сборки автоматически разрешает граф зависимостей, скачивая не только нужную библиотеку, но и все её внутренние зависимости.
Когда разработчик добавляет новую зависимость в pom.xml, система выполняет следующие действия:
- Проверяет локальный репозиторий на наличие указанной версии.
- Если версия найдена, она подключается к проекту.
- Если версия отсутствует, система обращается к удаленным репозиториям, перечисленным в конфигурации.
- Скачивает саму библиотеку и все её транзитивные зависимости (зависимости зависимостей).
- Сохраняет полученные файлы в локальный кэш для будущего использования.
Транзитивные зависимости создают сложную сеть связей между компонентами. Например, библиотека A зависит от библиотеки B, а библиотека B зависит от библиотеки C. При подключении A система автоматически подтянет B и C. Это упрощает жизнь разработчику, но иногда приводит к конфликтам версий, когда разные части проекта требуют разные версии одной и той же библиотеки.
Конфликты версий решаются механизмом приоритета. Maven выбирает первую зависимость, встретившуюся в дереве, или использует стратегию "ближайшей" зависимости. Если возникает конфликт, система выводит предупреждение в консоль, указывая, какая версия была выбрана и почему. Разработчик может явно указать желаемую версию в pom.xml, чтобы переопределить поведение по умолчанию.
Типы зависимостей определяются атрибутом scope:
- compile: Стандартная зависимость, доступна на всех этапах.
- test: Доступна только во время компиляции и запуска тестов.
- provided — Предполагается, что среда выполнения предоставит библиотеку (например, сервер приложений).
- runtime: Не нужна для компиляции, но требуется во время выполнения.
- Система: Зависимость находится в локальной файловой системе и не скачивается из репозитория.
Maven
Как работает Maven?
Maven строится вокруг концепции Project Object Model (POM) — описания проекта в XML-формате. Файл pom.xml содержит метаданные, зависимости, плагины и настройки сборки. Проект следует стандартной структуре каталогов, что позволяет инструменту автоматизировать все этапы разработки без дополнительной конфигурации.
pom.xml содержит:
- метаданные (название, версия, автор);
- зависимости (библиотеки);
- плагины (для сборки, тестирования);
- настройки профилей (dev, prod).
POM является базовым модулем Maven. Это специальный XML-файл, который всегда хранится в базовой директории проекта и называется pom.xml. Файл POM содержит информацию о проекте и различных деталях конфигурации, которые используются Maven для создания проекта.
Maven делегирует компиляцию плагину maven-compiler-plugin. При выполнении фазы compile плагин:
- Сканирует каталог
src/main/javaрекурсивно - Формирует список
.javaфайлов - Вызывает компилятор
javacс параметрами:-sourceи-targetиз свойств проекта-encodingизproject.build.sourceEncoding-classpathна основе разрешённых зависимостей
- Размещает
.classфайлы вtarget/classesс сохранением структуры пакетов
Компиляция тестов происходит отдельно через фазу test-compile с использованием каталога src/test/java и размещением результатов в target/test-classes. Класспат для тестов включает основные классы и зависимости с областью test.
mvn может быть видна в глобальном терминале, но не в IDE-терминале, потому что переменные окружения загружаются при запуске терминала.
- глобальный терминал (cmd, bash, zsh) читает PATH, где прописан Maven;
- IDE (IntelliJ IDEA, VS Code, Eclipse) запускает свой встроенный терминал с тем окружением, с которым запущена сама IDE.
Если вы установили Maven после запуска IDE, то терминал IDE об этом не знает. Если вы запустили IDE не из терминала, она не наследует ваши shell-конфиги(.bashrc, .zshrc). В Windows разница между системными и пользовательскими переменными.
Лечится такое перезапуском IDE или ручным указанием PATH внутри терминала IDE.
Чтобы загрузить все зависимости, нужно написать команду:
mvn clean install
Разбор:
mvnзапускает Maven в текущем проекте и читает егоpom.xml.- Фаза
cleanудаляет каталогtarget, чтобы убрать артефакты предыдущих сборок. - Фаза
installзапускает полный цикл до установки и кладёт готовый артефакт в локальный репозиторий~/.m2/repository. - Команда удобна для проверки, что проект полностью собирается "с нуля" и доступен другим локальным модулям.
Здесь:
cleanудаляетtarget/(старые class-файлы);installсобирает проект и кладёт результат в локальный репозиторий.
Чтобы узнать точные названия и версии, нужно идти:
- в Maven Central Search;
- MVNRepository.com;
- или искать внутри IDE, к примеру IDEA умеет искать зависимости по имени.
Версионность
Зависимости обновляются и выкладываются, теряют актуальность и устаревают, поэтому имеют версионные отличия. Когда мы обновляем зависимости, Maven смотрит в локальный кэш, и если зависимость релизная, то использует её. Если это SNAPSHOT, то проверяет по умолчанию раз в день, или при наличии флага -U:
mvn clean install -U
Разбор:
- Ключ
-Uозначает--update-snapshotsи форсирует обновление SNAPSHOT-зависимостей. - Команда полезна, когда в удалённом репозитории уже появился более свежий snapshot, а локальный кэш ещё не обновился.
- Флаг не меняет версии в
pom.xml, он только принудительно перепроверяет и скачивает артефакты. - Остальная часть команды (
clean install) выполняет стандартный цикл очистки, сборки, тестов и установки.
Флаг -U (--update-snapshots) — заставляет перекачать SNAPSHOT-зависимости (нестабильные версии).
Если зависимость не будет найдена, то Maven идёт в репозитории, объявленные в pom.xml / settings.xml.
Но Maven никогда не обновляет версию автоматически. Если нужно перейти с 1.0 на 1.1 — надо изменить pom.xml вручную.
Проверка репозиториев и зависимостей:
mvn help:effective-pom
mvn dependency:tree
Разбор:
help:effective-pomпоказывает итоговый POM после применения родительских POM, профилей и значений по умолчанию.dependency:treeстроит дерево зависимостей и помогает увидеть транзитивные библиотеки.- Эти команды часто применяют при диагностике конфликтов версий и неожиданных подключений.
- Они не изменяют проект, а дают диагностическую картину текущей конфигурации.
Если будет опечатка в группе или артефакте, то Maven не соберёт проект.
Неизбежные сложности с настройкой версий и зависимостей являются нормальной частью работы в Java. Экосистема огромна и разнообразна, поэтому периодическая "танцевальная" настройка окружения неизбежна. Разработчики сталкиваются с необходимостью обновлять JDK, менять версии Maven, корректировать pom.xml и решать конфликты версий.
Ключевой параметр в pom.xml говорит "компилируй так, чтобы работало на этой версии":
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
Разбор:
- Блок
<properties>задаёт общие параметры, которые используют плагины сборки. maven.compiler.sourceопределяет, какой синтаксис языка разрешён компилятору.maven.compiler.targetзадаёт формат байткода, совместимый с указанной версией JVM.- Эти свойства помогают синхронизировать ожидания проекта и фактическую JDK в окружении сборки.
Одной из распространенных проблем при сборке является несоответствие версий Java, Maven и зависимостей. Каждый компонент экосистемы имеет свои требования к версии языка и инструментария. Компилятор Java требует указания целевой версии (target), версии исходного кода (source) или единого параметра release. Если эти параметры не согласованы с установленным JDK, который реально запускает javac, сборка падает.
Ошибки "release version … not supported" и "invalid target release"
Maven и IDE передают компилятору флаг --release N (или пары -source / -target). Сообщения выглядят так:
error: release version 25 not supported
или (в старых логах Maven):
invalid target release: 25
Смысл одного и того же: JDK, которым идёт компиляция, не умеет собирать проект под указанную версию N.
| Ситуация | Что в pom.xml | Какой JDK запускает сборку | Что сделать |
|---|---|---|---|
| Цель слишком новая | maven.compiler.release 25, source/target 25 | JDK 17 или 21 | Поставить JDK ≥ 25 или снизить release до 17/21 |
| Цель слишком старая | release 5, source/target 1.5 | JDK 21 и новее | Поднять минимум до 8 (JDK 21+ не компилирует в Java 5/6) |
| Разные JDK в терминале и IDE | В pom — 21 | В терминале JDK 17, в IDEA — 21 | Выровнять Project SDK / JAVA_HOME и java -version |
Устаревший maven-compiler-plugin | В pom указана Java 25 | JDK 25 установлен | Явно указать плагин 3.13+ (см. ниже) |
Проверка окружения:
java -version
javac -version
mvn -version
Разбор:
java -versionпоказывает версию рантайма JVM, которая запускает Java-приложения.javac -versionпоказывает версию компилятора.mvn -versionдополнительно выводит, какой Java runtime использует сам Maven.- Сравнение этих трёх значений позволяет быстро обнаружить рассинхрон IDE/терминала и причину ошибок компиляции.
В выводе mvn -version смотрите строку Java version — именно этот JDK использует Maven из терминала.
Рекомендуемая настройка в pom.xml (одно значение вместо пары source/target):
<properties>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
Разбор:
maven.compiler.releaseобъединяет контроль исходного синтаксиса и целевого байткода одним параметром.- Это более надёжный современный вариант, чем отдельные
sourceиtarget. project.build.sourceEncodingфиксирует кодировку исходников и ресурсов, чтобы избежать проблем с текстом на разных ОС.- Такой набор снижает риск нестабильных сборок в команде и CI.
Явное объявление плагина, если свойства не подхватываются или нужна свежая Java:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
</plugins>
</build>
Разбор:
- Секция
<build><plugins>подключает плагины, расширяющие стандартный lifecycle Maven. maven-compiler-pluginотвечает за вызовjavac.<version>фиксирует конкретную версию плагина, что делает сборку воспроизводимой.<configuration><release>21</release>принудительно задаёт целевую версию Java для компиляции.- Явная конфигурация особенно полезна в проектах с разными JDK на машинах разработчиков.
Не указывайте в pom.xml версию Java выше, чем установленный JDK (например, 25 при JDK 17), если вы не планируете сразу обновлять среду. Для учебных и корпоративных проектов на 2026 год разумные значения — 17 или 21.
После смены версии в pom.xml выполните mvn clean compile и перезапустите IDE, чтобы подтянулся тот же JDK.
Настройки версий в pom.xml (классический вариант через source/target):
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<java.version>17</java.version>
</properties>
Эти свойства сообщают Maven, какую версию Java использовать для компиляции. Если проект использует функции, появившиеся в Java 17 (например, switch выражения или var), а целевая версия стоит на уровне 8, компилятор выдаст ошибку синтаксиса — даже при "свежем" JDK.
Минимальная версия Maven также важна. Новые версии Maven поддерживают новые возможности синтаксиса pom.xml и улучшают работу с зависимостями. Старые версии Maven могут не понимать современные конструкции, что приведет к ошибкам парсинга. Рекомендуется использовать актуальную стабильную версию инструмента.
Версии зависимостей должны соответствовать версии Java. Некоторые библиотеки требуют минимум Java 11 или Java 17 для корректной работы. Попытка запустить такую библиотеку на Java 8 вызовет ошибку времени выполнения NoSuchMethodError или ClassNotFoundException. Документация каждой библиотеки содержит информацию о требуемой версии платформы.
Если разработчик не знает точного названия, группы или версии зависимости, поиск должен проводиться через специализированные ресурсы. Основным источником информации является сайт Maven Central Search. На нем доступен полный индекс всех публичных библиотек. Пользователь вводит ключевые слова, описывающие функционал, который нужен (например, "JSON parsing" или "HTTP client"), и получает список подходящих вариантов.
Результаты поиска показывают:
groupId: Группа организации-разработчика.artifactId: Имя самой библиотеки.version: Доступные версии.- Описание: Краткое пояснение назначения библиотеки.
Альтернативный способ поиска — использование автозаполнения в IDE. При попытке подключить класс из неизвестной библиотеки среда разработки подсказывает возможные варианты импорта. Инструмент автоматически генерирует нужный блок <dependency> в pom.xml с правильными параметрами. Это избавляет от необходимости вручную искать названия и проверять их правильность.
Для уточнения версии полезно смотреть на страницу библиотеки в репозитории. Там отображается история изменений, дата последнего релиза и список известных проблем. Часто рекомендуется использовать последние стабильные версии, избегая бета-релизов, если проект не требует экспериментальных функций.
Локальный JAR в репозиторий Maven:
mvn install:install-file \
-Dfile=lib/mylib.jar -DgroupId=com.example -DartifactId=mylib \
-Dversion=1.0 -Dpackaging=jar
Разбор:
- Цель
install:install-fileдобавляет внешний локальный JAR в Maven-репозиторий пользователя. -Dfileуказывает путь к самому бинарному файлу.-DgroupId,-DartifactId,-Dversionформируют Maven-координаты артефакта.-Dpackaging=jarзадаёт тип артефакта.- После установки такой артефакт можно подключать в
pom.xmlкак обычную зависимость.
Механизм обновления зависимостей базируется на регулярной сверке версий в локальном кэше с версиями в удаленных хранилищах. По умолчанию Maven проверяет наличие новых версий раз в день или при наличии специального флага. При запуске процесса система отправляет запрос к указанному в pom.xml репозиторию (например, Maven Central). Сервер возвращает список доступных версий артефакта.
Если локальная версия отличается от доступной, система предлагает обновление. Однако по умолчанию Maven не обновляет зависимости автоматически, если они уже присутствуют в кэше. Это сделано для стабильности сборки: случайное обновление библиотеки может сломать работающий код. Для форсирования проверки используется флаг -U или настройка <updateSnapshots>true</updateSnapshots> в файле конфигурации.
Проверка репозиториев происходит в строгом порядке. Сначала система обращается к локальному репозиторию. Если файл найден, он используется. Если нет, идет очередь к удаленным хранилищам, перечисленным в settings.xml или pom.xml. Обычно первым указывается официальный репозиторий Maven Central, затем корпоративные хранилища или приватные зеркала. Если ни один из источников не содержит требуемый файл, сборка прерывается с ошибкой.
При работе с SNAPSHOT-версиями (разработочными версиями) проверка происходит чаще. Эти версии помечаются суффиксом -SNAPSHOT и предполагают постоянные изменения. Система обязана проверять их наличие в репозитории каждый раз перед сборкой, чтобы получить актуальный код. Обычные релизные версии (1.0.0, 2.3.1) считаются неизменными и не требуют постоянной проверки после первого скачивания.
Полная пересборка с обновлением SNAPSHOT-зависимостей:
mvn clean install -U
Разбор:
- Это полный цикл сборки с принудительным обновлением snapshot-артефактов.
- Команда часто используется в CI и при отладке проблем с "залипшим" локальным кэшем.
- Сначала очищается
target, затем пересчитываются зависимости, запускаются тесты и выполняется локальная установка. - Флаг
-Uвлияет только на обновление зависимостей, а не на изменение версий проекта.
CLI-команды Maven
mvn clean
mvn compile
mvn test
mvn package
mvn install
mvn deploy
mvn dependency:tree
mvn dependency:resolve
mvn clean install -U
mvn package -DskipTests
mvn -T 1C package
Разбор:
-
Блок перечисляет самые частые команды жизненного цикла Maven.
-
Последовательность
clean → compile → test → package → install → deployотражает путь от исходников до публикации артефакта. -
dependency:treeиdependency:resolveпомогают анализировать граф зависимостей. -
-DskipTestsускоряет сборку, если нужно временно пропустить тестовый этап. -
-T 1Cвключает параллельное выполнение задач с числом потоков по числу ядер CPU. -
clean — удаляет
target/. -
compile / test / package / install / deploy — фазы жизненного цикла.
-
dependency:tree / dependency:resolve — граф и кэш зависимостей.
-
-DskipTests — пропуск тестов; -Dmaven.test.skip=true — только запуск тестов.
-
-T 1C — параллельная сборка по числу ядер.
pom.xml
Базовый файл pom.xml содержит следующие секции:
Код ITЗагрузка примера кода…
Разбор:
- Корневой тег
<project>и namespace определяют формат POM-модели. - Блок координат (
groupId,artifactId,version) формирует уникальный идентификатор артефакта. - Секция
<dependencies>описывает внешние библиотеки и их scope. - Секция
<build><plugins>задаёт поведение сборки, включая компиляцию и дополнительные шаги. maven-compiler-pluginв примере фиксирует версию Java для компиляции исходного кода.
Секция <properties> задаёт переменные, используемые в других частях файла. Плагины в секции <build> расширяют стандартный жизненный цикл — компилятор настраивает версию Java, Surefire запускает тесты, Assembly создаёт исполняемые JAR-файлы.
Фазы Maven
Maven работает по жизненному циклу сборки проекта, который состоит из фаз. Каждая фаза представляет собой этап в процессе создания артефакта:
- validate - проверяет корректность проекта и наличия необходимых данных;
- compile - компилирует исходный код проекта;
- test – запускает юнит-тесты;
- package - упаковывает скомпилированный код в JAR/WAR/SO и т.д.;
- verify - выполняет проверки после упаковки перед установкой;
- install - устанавливает артефакт в локальное хранилище Maven;
- deploy - передаёт артефакт в удалённый репозиторий (например, Nexus, Artifactory).
Можно вызвать одну из фаз:
mvn compile
mvn package
mvn install
mvn package (см. блок выше) запускает все предшествующие фазы. Пропуск тестов:
mvn package -DskipTests
Файлы проекта распределены по строгой стандартной структуре:
| Путь | Назначение |
|---|---|
/Проект | Общая папка проекта |
/Проект/pom.xml | Главный конфигурационный файл (Maven) |
/Проект/src | Директория, где хранится весь исходный код Java-проекта |
/Проект/src/main | Основной код проекта |
/Проект/src/main/java | Исходные файлы Java, организованные в пакетной структуре |
/Проект/src/main/java/com/mycompany/project | Пример пакета в проекте |
/Проект/src/main/resources | Ресурсы: конфигурационные файлы, локализация, изображения, CSS, JS и другие не-кодовые файлы |
/Проект/src/test | Тестовый код, не включаемый в финальную сборку |
/Проект/src/test/java | Тестовые классы (например, с использованием JUnit, TestNG) |
/Проект/src/test/resources | Конфигурация и ресурсы, используемые при тестировании |
/Проект/target | Каталог для автоматически генерируемых файлов (сборка, артефакты, временные файлы) |
Структура каталогов Maven
my-app/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── app/
│ │ │ └── Main.java
│ │ └── resources/
│ │ └── application.properties
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── app/
│ │ └── MainTest.java
│ └── resources/
│ └── test-config.properties
└── target/
├── classes/
├── test-classes/
└── my-app-1.0.0.jar
Каталог target создаётся автоматически при сборке и содержит все промежуточные и финальные артефакты. Его содержимое удаляют через mvn clean (см. блок CLI ниже).
Управление зависимостями в Maven
Maven автоматизирует загрузку библиотек через централизованную систему координат. Каждая зависимость описывается тремя атрибутами:
groupId— организация или домен владельца библиотекиartifactId— имя библиотекиversion— конкретная версия
Пример объявления зависимости в pom.xml:
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
При первой сборке Maven проверяет локальный репозиторий ~/.m2/repository. Если артефакт отсутствует, инструмент обращается к центральному репозиторию по адресу https://repo.maven.apache.org/maven2, скачивает библиотеку и все её транзитивные зависимости, сохраняя их локально. Последующие сборки используют кэшированные файлы без сетевых запросов.
Транзитивные зависимости разрешаются автоматически. Если библиотека A зависит от B версии 2.0, а проект напрямую использует B версии 1.5, Maven применяет правила разрешения конфликтов для выбора единой версии.
Maven разрешает зависимости в три этапа:
- Анализ секции
<dependencies>вpom.xml - Рекурсивное извлечение транзитивных зависимостей из метаданных артефактов
- Применение правил разрешения конфликтов версий:
- Ближайший путь в дереве зависимостей
- Явное указание версии в
<dependencyManagement> - Порядок объявления в родительском POM
Зависимости классифицируются по области действия (scope):
compile— доступны во время компиляции и выполнения (значение по умолчанию)test— только для тестов, не попадают в финальный артефактruntime— не нужны для компиляции, требуются при запускеprovided— предоставляются окружением выполнения (например, сервлеты в веб-контейнере)
Артефакт Maven
★ Артефакт в Maven – это результат сборки проекта, например, JAR-файл, который содержит код, библиотеки, ресурсы и метаданные.
Каждый артефакт имеет уникальный идентификатор, состоящий из элементов:
- groupId – com.example – организация или домен;
- artifactId – my-app – имя проекта или библиотеки;
- version – 1.0.0., 2.1.3-SNAPSHOT – версия.
Пример:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version>
</dependency>
Это будет ссылка на артефакт:
org.springframework.boot:spring-boot-starter-web:2.7.0
Артефакты бывают следующих видов:
- .jar – обычные Java-библиотеки;
- .war – веб-приложения;
- .pom – описание проекта;
- .aar – Android-библиотеки..
Репозиторий
★ Репозиторий – это место, где хранятся артефакты. Они могут храниться локально (локальный репозиторий), в общедоступном репозитории Maven (центральный), и в удалённом (частном), для приватных артефактов.
При первом использовании зависимости Maven скачивает её из центрального репозитория, и сохраняет в локальный. При повторном использовании уже берёт из локального. То есть, добавляя зависимость в pom.xml, мы скачиваем и сохраняем локально в папку ~/.m2/repository.
Пошаговое создание проекта Maven
- Установите Apache Maven и проверьте доступность в PATH:
mvn --version
- Выполните генерацию шаблона проекта:
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=my-app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
- Перейдите в созданную директорию:
cd my-app
- Откройте файл
src/main/java/com/example/App.javaи замените содержимое:
package com.example;
public class App {
public static void main(String[] args) {
System.out.println("Привет из Maven!");
}
}
- Соберите проект:
mvn package
- Запустите приложение:
java -cp target/my-app-1.0.0.jar com.example.App
Начиная с Java 11 JavaFX не входит в JDK — Maven подтягивает его как зависимость; в IDEA может понадобиться Reload Maven Projects. Запуск через Maven:
mvn javafx:run
Точка входа в Maven (Main-Class)
В pom.xml нет отдельного поля "точка входа". При сборке плагины записывают в манифест JAR атрибут Main-Class — полное имя класса с методом public static void main(String[] args). См. также манифест JAR и синтаксис main в основах Java.
Практика в NetBeans и shade-плагин для запуска вне IDE: Maven в NetBeans.
Обычный JAR — maven-jar-plugin
Для проекта с пакетом org.coolcompany и классом Main добавьте или измените блок <build>:
Код ITЗагрузка примера кода…
Чтобы запускать другой класс (например, Test в том же пакете), создайте Test.java с тем же сигнатурой main и замените значение <mainClass> на org.coolcompany.Test. Метод test() сам по себе точкой входа не является — JVM ищет именно main.
Сборка и запуск:
mvn clean package
java -jar target/my-app-1.0.0.jar
Проверка: откройте JAR как ZIP и посмотрите META-INF/MANIFEST.MF — там должна быть строка Main-Class: org.coolcompany.Test (или выбранный класс).
Fat JAR (зависимости внутри одного файла)
Если нужен исполняемый архив со всеми библиотеками, используйте maven-shade-plugin и укажите mainClass в ManifestResourceTransformer (подробный пример — в Maven в NetBeans).
Запуск без пересборки — exec-maven-plugin
Удобно при разработке: класс для запуска задаётся в плагине, pom.xml менять реже, чем при смене mainClass в jar-plugin.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<mainClass>org.coolcompany.Test</mainClass>
</configuration>
</plugin>
mvn exec:java
В IntelliJ IDEA можно запустить любой класс с main через Run без правок pom.xml.
Spring Boot
Точка входа обычно определяется классом с @SpringBootApplication. Явная настройка в pom.xml нужна редко; см. Spring Boot.
| Сценарий | Плагин | Запуск |
|---|---|---|
| Обычный JAR | maven-jar-plugin | java -jar target/....jar |
| JAR + все зависимости | maven-shade-plugin | java -jar target/....jar |
| Быстрый запуск при разработке | exec-maven-plugin | mvn exec:java |
| Spring Boot | spring-boot-maven-plugin | mvn spring-boot:run |
Gradle
Практический старт: Gradle — практический старт.
Как работает Gradle?
Gradle – система автоматической сборки, построенная с учетом принципов Maven, но предоставляющая дополнительные возможности на языках Groovy и Kotlin вместо традиционной XML-образной формы представления конфигурации проекта. Это позволяет писать логику сборки как обычный код — использовать переменные, циклы, условия и функции.
Основные компоненты проекта Gradle:
build.gradleилиbuild.gradle.kts— основной файл сборкиsettings.gradle— настройки мультипроектной структурыgradle/— обёртка Gradle для кроссплатформенного запуска без глобальной установки
Gradle вводит концепцию задач (Задачи) как атомарных единиц работы. Задачи могут зависеть друг от друга, формируя направленный ациклический граф выполнения. Инкрементальная сборка анализирует изменения входных файлов и пересобирает только затронутые модули, что ускоряет повторные сборки.
Принцип разделения на src/main и src/test аналогичен Maven, но конфигурация хранится в build.gradle, а не в pom.xml. Отличие есть в папке для автоматически сгенерированных файлов – в Maven они хранятся по пути /target, а в Gradle - /build.
Gradle использует задачу compileJava из плагина java. Процесс аналогичен Maven, но с дополнительными оптимизациями:
- Инкрементальная компиляция — анализ изменений на уровне классов
- Демон компиляции — фоновый процесс, сохраняющий состояние между запусками
- Параллельная компиляция — использование нескольких ядер процессора
Настройка компилятора происходит через блок toolchain, который автоматически выбирает установленную JDK подходящей версии или загружает её при отсутствии. Это устраняет зависимость от переменной окружения JAVA_HOME.
build.gradle
Конфигурация на Groovy DSL:
Код ITЗагрузка примера кода…
Конфигурация на Kotlin DSL (build.gradle.kts):
Код ITЗагрузка примера кода…
Оба формата эквивалентны по функционалу. Kotlin DSL обеспечивает строгую типизацию и автодополнение в IDE, Groovy DSL — более лаконичный синтаксис.
CLI-команды Gradle
Управление жизненным циклом:
./gradlew clean— удаляет каталогbuild;
./gradlew clean
./gradlew build— выполняет полную сборку (компиляция, тестирование, создание артефакта);
./gradlew build
./gradlew compileJava— компилирует только основной код;
./gradlew compileJava
./gradlew test— запускает только тесты;
./gradlew test
./gradlew jar— создаёт JAR-файл без выполнения тестов;
./gradlew jar
./gradlew publishToMavenLocal— устанавливает артефакт в локальный кэш Maven (~/.m2/repository);
./gradlew publishToMavenLocal
./gradlew run— запускает приложение (требует плагин application).
./gradlew run
Информационные команды:
./gradlew Задачи --all— отображает все доступные задачи с описанием;
./gradlew Задачи --all
./gradlew dependencies— выводит дерево зависимостей.
./gradlew dependencies
Полезные флаги и режимы:
-x test — пропускает выполнение тестов (например, ./gradlew build -x test);
--parallel — включает параллельное выполнение задач;
--continuous (или -t) — непрерывный режим: сборка перезапускается при изменении исходных файлов.
Сборка в Gradle
Стандартный жизненный цикл:
gradle build
Этапы:
classes— компиляция основного кодаtestClasses— компиляция тестовtest— выполнение тестовjar— создание JAR-артефактаassemble— агрегация всех артефактов
Результаты сохраняются в каталоге build:
build/
├── classes/
│ ├── java/main/ # скомпилированные классы
│ └── java/test/ # скомпилированные тесты
├── libs/
│ └── my-app-1.0.0.jar
├── reports/tests/ # отчёты о тестировании
└── tmp/ # временные файлы
Gradle отслеживает состояние входных и выходных файлов каждой задачи. При повторной сборке без изменений исходного кода задачи помечаются как актуальные (UP-TO-DATE) и пропускаются.
Gradle использует конфигурации вместо областей действия:
implementation— зависимости для компиляции и выполнения, скрыты от потребителей библиотекиapi— зависимости, видимые потребителям (для библиотек)testImplementation— зависимости только для тестовruntimeOnly— зависимости только для выполнения
Преимущество подхода — контроль видимости транзитивных зависимостей. При использовании implementation зависимости не "утекают" в проекты, использующие вашу библиотеку, что снижает риск конфликтов версий.
Разрешение зависимостей происходит лениво — только при выполнении задач, требующих класспат. Это ускоряет запуск Gradle для операций, не связанных со сборкой (например, gradle Задачи).
gradle Задачи
Запуск проекта Gradle
Gradle предоставляет несколько способов запуска приложения:
- Через задачу
runплагинаapplication:
gradle run
- Через обёртку (без глобальной установки Gradle):
./gradlew run # Linux/macOS
gradlew.bat run # Windows
- Создание исполняемого JAR с манифестом:
jar {
manifest {
attributes 'Main-Class': 'com.example.App'
}
}
Запуск после сборки:
java -jar build/libs/my-app-1.0.0.jar
Обёртка gradlew скачивает указанную версию Gradle при первом запуске и использует её для всех последующих сборок, гарантируя воспроизводимость независимо от окружения разработчика.
Сравнение Maven и Gradle
Краткое сравнение Maven и Gradle
| Критерий | Maven | Gradle |
|---|---|---|
| Тип конфигурации | XML | Groovy/Kotlin DSL |
| Файл конфигурации | pom.xml | build.gradle |
Команды в Maven и Gradle
| Критерий | Maven | Gradle |
|---|---|---|
| Компиляция | mvn compile | gradle compileJava |
| Запуск тестов | mvn test | gradle test |
| Сборка JAR/WAR | mvn package | gradle build |
| Установка в локальный кэш | mvn install | gradle publishToMavenLocal |
| Очистка кэша | mvn clean | gradle clean |
| Запуск приложения | mvn exec:java | gradle run |
| Пропустить тесты | mvn install -DskipTests | gradle build -x test |
| Обновить зависимости | mvn dependency:resolve | gradle dependencies |
| Создать проект | mvn archetype:generate | gradle init |
| Показать список задач | mvn help:describe | gradle Задачи |
Аналогичные секции в pom.xml и build.gradle
| Maven | Gradle |
|---|---|
<groupId> | group |
<artifactId> | Имя проекта (из settings.gradle) |
<version> | version |
<properties> | Переменные в ext {} |
<dependencies> | dependencies {} |
maven-compiler-plugin | java.toolchain |
Gradle стал стандартом для:
- Android-разработки — официальная система сборки Android Studio
- Spring Boot — генератор проектов start.spring.io предлагает Gradle по умолчанию
- Мультипроектных систем — поддержка иерархии проектов с общими зависимостями
- Кастомных сценариев — публикация в репозитории, генерация документации, деплой на серверы
Гибкость скриптов позволяет интегрировать любые внешние инструменты — запускать утилиты командной строки, обрабатывать файлы, взаимодействовать с веб-сервисами.
Структура проекта Gradle
my-app/
├── build.gradle # или build.gradle.kts
├── settings.gradle
├── gradlew
├── gradlew.bat
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── App.java
│ │ └── resources/
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── AppTest.java
│ └── resources/
└── build/ # генерируется автоматически
Каталог gradle/wrapper содержит обёртку для кроссплатформенного запуска. Файл gradle-wrapper.properties указывает версию Gradle:
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
Пошаговое создание проекта Gradle
- Установите Gradle или используйте обёртку из другого проекта.
- Инициализируйте новый проект:
gradle init --type java-application \
--project-name my-app \
--package com.example \
--dsl groovy
- Система предложит выбрать вариант тестового фреймворка (JUnit 4, JUnit 5, TestNG). Выберите JUnit Jupiter (JUnit 5).
- Откройте сгенерированный файл
src/main/java/com/example/App.java:
package com.example;
public class App {
public String getGreeting() {
return "Привет из Gradle!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
}
}
- Соберите и запустите проект:
./gradlew build
./gradlew run
Gradle автоматически скачает зависимости из mavenCentral(), скомпилирует код с использованием JDK 17 (согласно настройкам toolchain), запустит тесты и выполнит основной класс. Все этапы логируются с указанием затраченного времени и статуса каждой задачи.
Работа с Java без систем сборки
Разработка на Java возможна без Maven и Gradle.
Минимальный рабочий процесс:
- Создайте структуру каталогов вручную:
mkdir -p src/com/example/app
mkdir -p bin
- Напишите класс
src/com/example/app/Main.java:
package com.example.app;
public class Main {
public static void main(String[] args) {
System.out.println("Прямая компиляция");
}
}
- Скомпилируйте вручную:
javac -d bin -sourcepath src src/com/example/app/Main.java
- Запустите:
java -cp bin com.example.app.Main
Для проектов с зависимостями потребуется вручную скачивать JAR-файлы, формировать класспат через флаг -cp и отслеживать совместимость версий. Сборка артефактов потребует использования утилиты jar с ручным созданием манифеста.
Такой подход применим для учебных задач, скриптов или микропроектов. Для коммерческой разработки, командной работы и поддержки сложных систем ручное управление становится непрактичным из-за роста объёма рутинных операций и риска ошибок. Системы сборки автоматизируют повторяющиеся действия, обеспечивают воспроизводимость и интеграцию с инструментами непрерывной интеграции.
Практический ориентир по выбору
Чтобы материал из статьи быстрее "приземлялся" в реальную работу, удобно держать короткий маршрут выбора.
| Ситуация | Что выбрать | Почему |
|---|---|---|
| Учебный мини-проект, 1 модуль | Maven | Предсказуемая структура и понятные фазы сборки |
| Нужен быстрый build и гибкие скрипты | Gradle | Инкрементальная сборка и DSL под кастомные задачи |
| Большой корпоративный проект | То, что принято в команде | Важнее единый стандарт и воспроизводимость CI |
| Временный эксперимент | javac + java | Минимальный порог входа, без лишней инфраструктуры |
Сначала соберите один и тот же маленький проект и в Maven, и в Gradle. После этого сравнение pom.xml и build.gradle воспринимается гораздо легче, чем "в теории".
Типичные ошибки и быстрые проверки
mvnилиgradleне найден в IDE-терминале — перезапустите IDE и проверьтеPATH.- Версия JDK в IDE и в терминале отличается — сверяйте
java -versionи настройки SDK проекта. - Зависимость добавлена, но класс не импортируется — выполните обновление проекта (
Reload/Reimport). - Сборка работает локально, падает в CI — зафиксируйте версию JDK и инструмента сборки явно.
Быстрый "диагностический минимум":
java -version
javac -version
mvn -version
./gradlew -v
Связанные статьи
- Базовый синтаксис и структура программы: Основные конструкции языка Java
- Типы, переменные и ссылки: Типы данных и переменные в Java
- Коллекции и практические структуры хранения: Коллекции в Java
- Разбор ошибок и пошаговое выполнение: Отладка Java-кода в IDE
Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.