Перейти к содержимому

Где хранятся скомпилированные maven ом файлы проекта

  • автор:

Подписаться на ленту

Like this

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.3.2953

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Сборка Java-проекта с использованием Maven

Этот урок освещает создание вами простого Java-приложения с использованием Maven.

Что вы создадите

Вы создадите простое приложение и соберете его с помощью Maven.

Что вам потребуется

  • Примерно 15 минут свободного времени
  • Любимый текстовый редактор или IDE
  • JDK 6 и выше

Как проходить этот урок

Как и большинство уроков по Spring, вы можете начать с нуля и выполнять каждый шаг, либо пропустить базовые шаги, которые вам уже знакомы. В любом случае, вы в конечном итоге получите рабочий код.

Чтобы начать с нуля, перейдите в Настройка проекта.

  • Загрузите и распакуйте архив с кодом этого урока, либо кнонируйте из репозитория с помощью Git: git clone https://github.com/spring-guides/gs-maven.git
  • Перейдите в каталог gs-maven/initial
  • Забегая вперед, установите Maven

Когда вы закончите, можете сравнить получившийся результат с образцом в gs-maven/complete .

Настройка проекта

Для начала вам необходимо настроить Java-проект перед тем, как собрать его Maven’ом. Т.к. урок посвящен Maven, сделаем проект максимально простым, насколько это возможно.

Создание структуры каталогов

В выбранном вами каталоге проекта создайте следующую структуру каталогов; к примеру, командой mkdir -p src/main/java/hello для *nix систем:

+-- src +-- main +-- java +-- hello

Внутри src/main/java/hello директории вы можете создать любые Java-классы, какие вы хотите. Для простоты и согласованности с остальной частью урока, Spring рекомендует вам создать два класса: HelloWorld.java и Greeter.java .

package hello; public class HelloWorld < public static void main(String[] args) < Greeter greeter = new Greeter(); System.out.println(greeter.sayHello()); >>
package hello; public class Greeter < public String sayHello() < return "Hello world!"; >>

Теперь, когда у вас есть проект, который вы можете собрать с Maven, вам нужно установит сам Maven.

Maven можно получить, скачав zip-файл с maven.apache.org/download.cgi. Необходимы только бинарные файлы, так что ищите ссылку на архив с именем apache-maven-version-bin.zip или apache-maven-version-bin.tar.gz.

Распакуйте архив и добавьте путь к каталогу bin в переменную окружения path.

Чтобы протестировать правильность установки Maven, запустите в командной строке:

mvn -v

Если всё было сделано правильно, то вы увидите сообщение примерно такого содержания:

Apache Maven 3.0.5 (r01de14724cdef164cd33c7c8c2fe155faf9602da; 2013-02-19 07:51:28-0600) Maven home: /usr/share/maven Java version: 1.7.0_09, vendor: Oracle Corporation Java home: /Library/Java/JavaVirtualMachines/jdk1.7.0_09.jdk/Contents/Home/jre Default locale: en_US, platform encoding: UTF-8 OS name: "mac os x", version: "10.8.3", arch: "x86_64", family: "mac"

Теперь у вас есть установленный Maven.

Создание простой сборки Maven

Теперь, когда Maven установлен, вам необходимо создать определение Maven-проекта. Maven-проекты определяются как XML-файлы с названием pom.xml. Помимо всего прочего, этот файл определяет имя проекта, версию, а также зависимости от сторонних библиотек.

Создайте файл с названием pom.xml в корневом каталоге проекта и наполните его следующим содержанием:


xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
org.springframework
gs-maven
jar
0.1.0




org.apache.maven.plugins
maven-shade-plugin
2.1


package

shade



implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
hello.HelloWorld








За исключением дополнительного элемента , это простейший из pom.xml файлов, необходимый для сборки Java проекта. Он включает следующие детали конфигурации проекта:

  • — версия POM-модели (всегда 4.0.0)
  • — группа или организация, к которой принадлежит проект. Чаще всего выражается в виде перевернутого наоборот доменного имени
  • — имя, которое будет передано библиотеке экземпляра(artifact) проекта (к примеру, имя его JAR или WAR файла)
  • — версия, с которой будет собран проект
  • — как проект должен быть упакован. По умолчанию, с «jar» упаковывается в JAR-файл, «war» — WAR-файл

Когда речь заходит о выборе схемы управления версиями, Spring рекомендует [семантическое управление версиями] semver.org подход.

На данном этапе мы имеем минимальное, но уже рабочее определение Maven-проекта.

Сборка Java кода

Теперь все готово для сборки проекта Maven’ом. Вы можете выполнить несколько этапов жизненного цикла сборки, включая компиляцию кода, создание библиотеки пакета(такого, как JAR-файл) и установку библиотеки в локальный репозиторий Maven зависимостей.

Попробуйте собрать, выполнив команду, приведенную ниже:

mvn compile

Этим вы запустите Maven, передав ему указание на выполнение задачи compile. Когда он закончит, вы должны найни скомпилированные .class файлы в target/classes директории.

Вряд ли вы захотите распостранять или работать напрямую с .class файлами, поэтому вам полее подойдет выполнение задачи package:

mvn package

Задача package включает компиляцию вашего Java кода, запуск тестов, а в конце упаковывает в JAR-файл в target директории. Название JAR-файла будет основано на и . К примеру, с минимальным pom.xml(см. выше), JAR-файл будет иметь название gs-maven-initial-0.1.0.jar.

Если вы изменили значение с «jar» на «war», то результатом будет WAR-файл в target директории вместо JAR-файла.

Maven также хранит репозиторий зависимостей на вашей локальной машине(обычно в .m2/repository директории в вашей домашней папке) для быстрого доступа к зависимостям проекта. Если вы хотите добавить JAR-файл вашего проекта в локальный репозиторий, тогда вам необходимо выполнить задачу install :

mvn install

Задача install включает компиляцию, тестирование, упаковку кода проекта, а затем копирование в локальный репозиторий, тем самым другие проекты смогут ссылаться на него как на зависимость.

Говоря о зависимостях, пришло время объявлять зависимости в Maven сборке.

Объявление зависимостей

Простой «Hello World» пример полностью автономный и не зависит от каких-либо дополнительных библиотек. Однако, большинство приложений зависит от внешних библиотек, с реализацией распостраненного и/или сложного функционала.

К примеру, предположим, что в дополнение к «Hello World!» вы хотите, чтобы приложение печатало текущую дату и время. Вы могли бы использовать функциональность из стандартных(native) Java библиотек, но мы можем сделать это и другими интересными способами, например с помощью Joda Time библиотеки.

Для начала, изменим HelloWorld.java , как показано ниже:

package hello; import org.joda.time.LocalTime; public class HelloWorld < public static void main(String[] args) < LocalTime currentTime = new LocalTime(); System.out.println("The current local time is: " + currentTime); Greeter greeter = new Greeter(); System.out.println(greeter.sayHello()); >>

Здесь HelloWorld использует Joda Time LocalTime класс для получения и печати текущего времени.

Если бы вы запустили mvn compile для сборки проекта сейчас, то получили бы ошибку сборки, потому что вы не объявили Joda Time компилируемую зависимость в сборке. Вы можете это исправить, добавив следующие строки в pom.xml(в пределах элемента):

 

joda-time
joda-time
2.2

Этот блок XML объявляет список зависимостей проекта. В частности, он объявляет единственную зависимость от Joda Time библиотеки. В элементе, зависимость определяется через описание трех вложенных элементов:

  • — группа или организация, к которой принадлежит зависимость.
  • — необходимая библиотека
  • — версия необходимой библиотеки

По умолчанию, все зависимости определены как зависимости. Т.е. они должны быть доступны во время компиляции(а если вы собираете WAR-файл, то в /WEB-INF/lib каталоге). Кроме того, вы можете добавить элемент, с одним из значений:

  • provided — зависимости, которые требуются для компиляции кода проекта, но которые будут доступны во время выполнения кода контейнером(например, Java Servlet API)
  • test — зависимости, которые используются для компиляции и запуска тестов, но не требуемые для сборки или выполнения кода проекта

Сейчас, если вы выполните mvn compile или mvn package , Maven должен будет разрешить Joda Time зависимость из Maven Central репозитория и успешно собрать проект.

Здесь полная версия pom.xml :


xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
org.springframework
gs-maven
jar
0.1.0




joda-time
joda-time
2.2







org.apache.maven.plugins
maven-shade-plugin
2.1


package

shade



implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
hello.HelloWorld








Полная версия pom.xml использует Maven Shade Plugin как удобный инструмент для создание выполняемого JAR-файла. Целью данного урока является показать, как начать работать с Maven, не используя, в частности, этот плагин.

Итог

Поздравляем! Вы создали простой, но эффективный файл сборки Maven для сборки Java проектов.

С оригинальным текстом урока вы можете ознакомиться на spring.io.

Apache Maven

Сегодня речь пойдёт о Maven. Это в первую очередь утилита для сборки Java проектов, но по факту является системой управления проекта в целом, определяет его структуру и, во многом, жизненный цикл. (Apache Maven is a software project management and comprehension tool. Project object model (POM)) Работая с базовыми сценариями в хорошо настроенном окружении, программисту не требуется глубоко вникать в тонкости этой технологии. Но стоит проекту Maven перестать собираться, как легко можно попасть в тупик, для выхода из которого требуется опыт и понимание определённых нюансов. Почему не находится плагин? Зачем он лезет в интернет? Почему падает деплой артефакта? Откуда взялась библиотека log4j первой версии? Почему сборка работает локально, а на Jenkins падает? У меня в IDE всё компилируется, а Maven что-то тупит. Вспоминать и фантазировать можно долго.

Многие скажут, что я утрирую, но Вы можете поверить, что люди переходили с Eclipse на IDEA после трёх и более лет разработки потому, что сложный maven проект отказывался нормально импортироваться в Eclipse, но коллеги пользовались IDEA и никто не мог помочь настроить его в Eclipse?

Но даже учитывая всё это, использование Maven — это необходимость и меньшее из зол. Maven заставляет всех разработчиков делать одинаково и более менее правильно. Это касается структуры проектов, расположения и имён определённых файлов, управлениями модулями, зависимостями и в определённой степени процессом релизов.

Как развивались некоторые проекты, пока их не мигрировали на maven? Все известные мне проекты собирались с помощью утилиты Ant. Не знаю, смог ли кто-то настроить компиляцию и сборку с использованием непосредственно утилиты javac, поставляемой вместе JDK а также shell или bat скриптов, но это было бы уж слишком безумно. Большинство вполне успешно обходилось утилитой Ant.

Давайте пофантазируем, как это было. Куда положить исходный код? Ну, допустим ./src/Main.java или ./src/com/example/Main.java, если с пакетами. Куда проперти файлы? Давайте туда же ./src/log4j.xml. Но не все, что-то положим в ./conf. Куда будем складывать скомпилированные файлы? Мне нравится ./dist. А тесты? В ./test/src, а данные для теста в ./test/*, то есть рядом с исходниками. Честно говоря, я подсматриваю в реальном проекте. Если вы уже имеете опыт разработки, то уже чувствуете отсутствие стандарта — вроде всё логично, но в то же время наобум. И на каждом новом проекте будет похоже, но по-другому. Кстати, а библиотеки мы куда положим? В ./lib, конечно же. Стоп! Что значит положим библиотеки, разве они не должны храниться централизованно и выкачиваться автоматически при необходимости? Нет, библиотеки скачивают, потом обычно из переименовывают из log4j-1.2.12.jar в log4j.jar, чтобы версию уже никак нельзя было определить, разве что её заботливо указали в MANIFEST файле внутри библиотеки. Естественно, библиотеки сохраняются и в системе контроля версий, и таким образом любой проект весит уже никак не меньше 20-50 мегабайт.

С библиотеками вообще очень неудобно — начинаешь новый проект и каждую библиотеку скачивать из интернета и сохранять в проекте неудобно, ещё и может понадобиться в IDE явно её добавлять. Но был найден удобный и эффективный подход, решающий все проблемы — мы будем копировать lib из проекта в проект. Со временем там окажутся все нужные нам библиотеки: логгеры, драйверы всех баз данных, spring, apache commons, junit, сервлеты.

картинки нет, но вы держитесь

Ну вот у нас есть исходные файлы, мы настроили IDE, указав пути к ним, добавили библиотеки. Пришло время показать наше приложение кому-то, а на местном наречии — «выложить». Выложить в тестовую среду или продакшен. В случае web приложения это означает, что нужно создать ZIP архив фиксированной структуры, состоящий из скомпиливанных классов, файлов настроек, библиотек и ещё пары специальных файлов. Этот архив называется WAR-архивом (или варником). Для всего этого и создаётся Ant сборка. Чаще всего это файл с названием build.xml, в довесок к которому идёт build.properties. Пример содержимого такого фэйла:

картинки нет, но вы держитесь

картинки нет, но вы держитесь

Команда завершается успешно, в папке ./target появился файл samples-maven-simple-1.0-SNAPSHOT.jar. В нём только сам pom.xml и MANIFEST.MF следующего содержания: Чаще всего это применяется к библиотекам логирования. Например, исключаем отовсюду log4j, а потом добавляем log4j-over-slf4j. Подробнее тут.

картинки нет, но вы держитесь

Добавлю один интересный сценарий связанный с тестированием, о котором не все знают. Все тесты располагаются в папке src/test, в все юнит тесты имеют постфикс «Test». По практикам разработки существуют ещё интеграционные тесты, которые могут использовать внешние сервисы и запускаются отдельно от юнит тестов. Для них иногда заводят отдельные модули и настройки surefire плагина. Можно поступить иначе — добавить к имени теста постфикс «IT» (полный список: **/IT*.java, **/*IT.java, **/*ITCase.java). Такие тесты запускаются командой «mvn verify», а отвечает за них специальный maven-failsafe-plugin. Он требует явного указания в pom.xml: То есть при настройках по умолчанию придётся ждать целый день, чтобы воспользоваться исправленной версией библиотеки! А если установить опцию ‘always’, то сборки начнут заметно тормозить при большом количестве snapshot зависимостей. Удобно при необходимости добавлять к аргументам команды сборки параметр «-U» (mvn clean package -U), тогда все снэпшоты будут принудительно обновлены. Процесс разработки можно выстроить следующим образом:

  1. Устанавливаем версию библиотеки 1.0-SNAPSHOT
  2. Устанавливаем версию зависимости в основном приложении в 1.0-SNAPSHOT
  3. Вносим изменения в библиотеку, выполняем deploy
  4. Пересобираем основное приложение, при необходимости с аргументом -U, тестируем
  5. Повторяем шаги 3-4 до тех пор, пока код не стабилизируется и все ошибки не будут исправлены
  6. Устанавливаем версию библиотеки 1.0
  7. Устанавливаем версию зависимости в основном приложении в 1.0
  8. Осуществляем финальные проверки и выходим в релиз. Если находим ошибки, возвращаемся на шаг 6, меняя версию на 1.0.1
  9. Начинаем работу над следующим релизом
  10. Устанавливаем версию библиотеки 1.1-SNAPSHOT
  11. Устанавливаем версию зависимости в основном приложении в 1.1-SNAPSHOT

Чтобы снэпшоты не накапливались в репозитории в неограниченном количестве, в Nexus и Artifactory существуют политика удаления старых версий. Поэтому иногда старые снэпшоты теряют свою актуальность или вообще пропадают из репозитория, хотя по хорошему последняя-то версия не должна удаляться. Следует руководствоваться следующим правилом: версия release не должна иметь snapshot зависимостей. Только в этом случае релизная версия представляет собой что-то финальное и не подверженное случайным факторам. Если же мы оперируем версиями snapshot, значит наш код часто меняется и при случае мы легко можем восстановить артефакт в репозитории, запустив команду deploy.

На этом пока оставим релизы и снэпшоты. Заметили, что вместе с обычным артефактом сборки в репозиторий попала ещё версия «jar-with-dependencies»? При этом группа, артефакт и версия у них совпадают. Это возможно благодаря дополнительному атрибуту зависимостей — classifier. При использовании assembly плагина в файле конфигурации assembly.xml нужно указать id. В нашей сборке id неявно устанавливается в «jar-with-dependencies». Результаты сборки плагином assembly ведут себя так же, как и основной артефакт. Зависимость будет выглядеть так, если понадобится:

   hipravin.samples samples-maven-simple 1.0-SNAPSHOT jar-with-dependencies  

Атрибут classifier также используется при загрузке исходного кода и документации javadoc. По умолчанию загружается только скомпилированный код, а пользователи нашей библиотеки не увидят никакой документации, а если попытаются посмотреть исходный код, то получат в лучшем случае декомпилированную версию. Это не очень удобно, поэтому лучше публиковать sources и javadoc. Для этого добавляем в pom.xml два плагина:

   org.apache.maven.plugins maven-source-plugin 3.2.1   attach-sources  jar      org.apache.maven.plugins maven-javadoc-plugin 3.2.0   attach-javadocs  jar    

Теперь при выполнении команды deploy в репозиторий будут загружены дополнительные артефакты с классификаторами «-sources» и «-javadoc», и соответствующая информация будет автоматически доступна в IDE разработчика, использующего нашу библиотеку.

Модули

До сих пор мы работали с приложением, состоящим из одного модуля. Однако модули — едва ли не главная функциональность Maven, сильнее всего влияющая на процесс проектирования и разработки приложений. Сегодня в эпоху микросервисов становится всё более популярно использовать один репозиторий (GIT) для одного сервиса. В этом случае объём кода и логики одного приложения часто не требует разделения на модули. Сейчас я не буду никак сравнивать монолит с микросервисной архитектурой. Многие работают с монолитом или как минимум c приложениями с большим объёмом кода в одном репозитории. В этом случае разделение кода на модули имеет тот же смысл, что разделение на пакеты, классы, методы.

Разделение на пакеты — по большей части логическое, визуальное, если не считать модификаторов доступа protected и default. При разделение на модули код одного модуля ни во время компиляции, ни во время исполнения ничего не знает о других модулях, если не установлена зависимость. Одна из ситуаций, когда модули жизненно необходимы — если в одном проекте уживаются вместе несколько приложений. Например, несколько web приложений, которые мы собираем в отдельные WAR архивы и может даже развертываем на разных серверах Apache Tomcat. Каждое приложение мы помещаем в отдельный модуль. Приложения не полностью различны, они как-то перекликаются, относятся к единому бизнес домену, поэтому возникают повторяющиеся классы и методы, то есть дублирование кода. Тогда мы выделяем отдельный модуль common, куда перемещаем все общие части. Потом нам хочется больше модулей, чтобы каждый отвечал за свою задачу, а не содержал сборную солянку разных утилит. Тогда в дополнение к common мы вводим модули security, model, dao и так далее. Просто чтобы в коде было чисто и аккуратно. Бонусом получаем скорость сборки, ведь нет смысла пересобирать модули, в которых не было изменений.

Код примера. Рассмотрим небольшое приложение, состоящее из нескольких модулей. Программа подсчитывает частоту появления различных слов во входном файле. В модуле common реализован сам алгоритм, модуль consoleapp содержит главный класс для запуска из консоли, а модуль webapp — Web приложение с REST сервисом. Между webapp и сonsoleapp нет зависимостей, но оба зависят от common. Можно представить, что приложение существует давно, а для работы с ним всегда использовалась консоль, но теперь решили добавить ещё и веб сервис. В коде приложения ничего показательного, его я приводить не буду, лучше сконцентрируюсь на Maven.

При создании проекта в корне я сразу удалил папку src, а в pom.xml установил свойство packaging в значение «pom». Также artifactId имеет окончание «-parent», но это необязательно, больше для удобства и потому что так принято.

  hipravin.samples.maven samples-maven-multiple-parent 1.0-SNAPSHOT pom 

Такой модуль называют родительским (parent) или иногда основным, главным. Он обычно не содержит исходного кода и артефактов сборки. Его предназначение — управлять остальными модулями. Все они должны быть перечислены в теге modules:

   common consoleapp webapp  

Все дочерние (child) модули наследуют свойства, зависимости, плагины от родительского модуля. Например, уровень языка для compiler плагина достаточно указать только в главном модуле. А вот зависимости в главном модуле указывать не стоит, потому что исключить их в дочерних модулях будет крайне затруднительно. Вместо этого в родительском модуле фиксируют список библиотек их версий, а в дочерних — лишь ссылаются на них. Выглядит это так: в главном модуле в pom.xml используется тег dependencyManagement, а в дочерних — dependency без версии:

  .   org.junit.jupiter junit-jupiter-engine 5.4.0 test      org.junit.jupiter junit-jupiter-engine  

Помимо перечисления версий библиотек в dependencyManagement по одной, существует дополнительный механизм указания версий для целой группы зависимостей — BOM (Bill Of Materials). Это очень полезно для проектов с большим количеством модулей (например, для spring: core, context, beans, web, jdbc, . ). Модуль webapp использует Spring Boot, BOM можно указать в главном модуле следующим образом:

      org.springframework.boot spring-boot-dependencies 2.2.6.RELEASE pom import  .    org.springframework.boot spring-boot-starter-web  

Ключевым здесь является значение параметра scope равное import.

Для проектов, использующих Spring Boot альтернативный вариант — указать в качестве родительского проекта spring-boot-starter-parent. То есть родительский модуль не обязательно должен располагаться рядом в том же проекте, он может загружаться и из удалённого Maven репозитория. В этом случае нужно установить свойство relativePath в пустое значение. Например, так:

   org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE  

При этом родительский модуль может быть только один.

Чтобы классы из модуля common были доступны в модуле consoleapp, нужно добавить зависимость так же, как ранее мы добавляли зависимость на библиотеку jackson.

   hipravin.samples.maven common $ 

Вместо версии 1.0-SNAPSHOT мы ссылаемся на версию родительского модуля, потому что неразумно иметь разные версии в рамках одного проекта, а дублировать эту версию многократно неудобно. На этом этапе может возникнуть определённая путаница, как в понимании происходящего, так и в работе самого Maven. Как мы знаем, зависимости загружаются из репозитория, либо берутся напрямую из папки .m2. Но мы ещё ни разу не собирали наш проект и тем более не выполняли install или deploy. В рамках одного проекта Maven в этом не нуждается — он выстроит дерево зависимостей наших модулей, причём именно дерево, а не граф, потому что циклы запрещены. Потом он осуществит сборку модулей в правильном порядке и при работе с каждым модулем все его зависимости уже будут обработаны. Если какой-то из модулей Maven упорно пытается искать в репозитории, то вероятно допущена ошибка в координатах зависимости.

Чтобы собрать весь проект целиком достаточно запустить команду «mvn package» в корне проекта. Так же с install и deploy. Так выглядит лог успешной сборки:

 . [INFO] Reactor Summary for samples-maven-multiple-parent 1.0-SNAPSHOT: [INFO] [INFO] samples-maven-multiple-parent . SUCCESS [ 1.012 s] [INFO] common . SUCCESS [ 10.054 s] [INFO] consoleapp . SUCCESS [ 1.032 s] [INFO] webapp . SUCCESS [ 4.769 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS 

Довольно редко возникает необходимость собирать только один модуль, однако если проект громоздкий и полный билд занимает минуты, то это может быть полезно. Для этого нужно указать список модулей для сборки, например один модуль webapp, а также параметр —also-make, чтобы были обработаны необходимые модули, от которых явно или неявно зависит webapp.

 clean package --projects webapp --also-make . [INFO] Reactor Summary for samples-maven-multiple-parent 1.0-SNAPSHOT: [INFO] [INFO] samples-maven-multiple-parent . SUCCESS [ 0.382 s] [INFO] common . SUCCESS [ 6.051 s] [INFO] webapp . SUCCESS [ 2.755 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS 

Заметим, что сейчас в проекте несколько раз дублируется версия родительского модуля. Это вполне допустимо, но при обновлении версии на, скажем, 1.0 или 1.1-SNAPSHOT, нам придётся обновлять код в нескольких местах, что создаёт вероятность ошибки, вызванной человеческим фактором. Хуже всего обновлять по памяти: тут, тут и тут, потому что легко можно случайно забыть или пропустить один из модулей. Если артефакты попадают в локальный репозиторий, то проект продолжит собираться без ошибок, но код одного из модулей будет использовать старую версию родительского модуля. Второй вариант — использовать автозамену по проекту (Ctrl+Shift+R в IDEA). Этот вариант плох тем, что можно случайно заменить лишнего — но чаще всего в этом случае проект просто не скопмилируется. Правильный способ обновлять версию — использовать плагин versions:

 mvn versions:set -DnewVersion=1.1-SNAPSHOT mvn versions:commit 

Команда «commit» здесь не имеет ничего общего с коммитом в системе контроля версий, это специфический этап работы плагина, удаляющий сохранённую копию pom.xml файла, которая создаётся на первом этапе.

Разное

О нескольких моментах стоит упомянуть для полноты картины, хоть им не нашлось места в демонстрационных проектах, описанных ранее.

Параметр optional. Модули webapp и consoleapp транзитивно зависят от всех библиотек, от которых зависит common. Эти библиотеки можно исключить в pom.xml каждого из этих модулей, используя exclusions, как мы уже видели. Альтернативно можно указать на этих зависимостях в модуле common параметр optional в значение true, тогда в webapp и consoleapp изменения не потребуются. Используется редко, не буду заострять внимание на этом.

Беспорядок с версиями зависимостей. Версия одной и той же библиотеки может быть указана явно единожды, транзитивно единожды, явно многократно, транзитивно многократно. Теоретически у Maven есть детерминированный алгоритм по определению версии. Практически лучше избегать неопределённости и изучать граф зависимостей, а также список библиотек, попадающий в артефакт сборки JAR with dependencies, WAR или EAR. Версия, указанная явно в pom.xml самого модуля имеет приоритет над транзитивными версиями. Однако если версии отличаются ещё и в group id / artifact id как, например, log4j и log4j2, то проблему можно решить только аккуратным исключением всех лишних зависимостей. А найти проблему можно, опять же, только анализом графа зависимостей и артефактов сборки.

Dependency scope. Для каждой зависимости можно указать scope. Часть значений влияет на то, в какие classpath попадает данная зависимость, другие просто определяют некое особое поведение. Мы уже встречали compile (значение по умолчанию), test и import. Я просто приведу список всех значений с небольшими комментариями. Я буду писать «сохраняется в lib» имея в виду, что библиотека попадает в classpath во время исполнения, а также копируется в директорию lib внутри артефактов сборки таких как WAR и EAR.

compile Значение по умолчанию. Зависимость доступна во время компиляции основного кода и тестов, сохраняется в lib. provided Зависимость доступна во время компиляции основного кода и тестов, но не сохраняется в lib. Применяется, когда библиотека предоставляется контейнером. Например, Weblogic предоставляет драйвер для соединения с базой данных. runtime Зависимость не доступна во время компиляции основного кода, доступна для компиляции тестов (не знаю зачем), но сохраняется в lib. Пример — драйвер базы данных, библиотеки логирования. test Зависимость не доступна во время компиляции основного кода, доступна для компиляции тестов, не сохраняется в lib. system Позволяет подключить библиотеку, jar файл которой располагается по определённому пути на файловой системе. Не рекомендую к использованию, в этом случае следует просто установить библиотеку в локальный репозиторий с помощью install-file. import Используется в dependencyManagement вместе c так называемым BOM (bill of materials)

Я не разбираю scope подробно, потому что в большинстве случаев достаточно compile и test, которые тривиальны, а остальные применяются по ситуации и редко приводят к скрытым ошибкам. А вот понять и запомнить чем отличается provided от runtime при первом знакомстве мало кому удаётся.

Жизненный цикл, фазы. Жизненный цикл состоит из фаз, которые мы можем указывать в строке запуска mvn. Каждый плагин запускается в ту фазу, которая указана в его конфигурации. Список всех фаз: validate, compile, test, package, verify, install, deploy. Опять же углубляться не буду, полагаю станет только непонятней. С практической точки зрения мы уже рассмотрели все основные фазы жизненного цикла.

Архетипы. Без использования IDE чтобы создать пустой maven проект нужно будет где-то взять заголовок xml файла и добавить в него как минимум координаты проекта. А если наш проект использует какой-то фреймворк, то потребуются ещё какие-нибудь обязательные настройки и файлы. В Maven существует понятие архетипа — способа создавать готовые проекты по шаблону с указанием набора параметров. Spring initializer, вероятно, внутри работает на основе архетипов. Однако это отдельный сайт, да и ещё со встроенной поддержкой в IDEA, поэтому пользоваться шаблонами Spring Boot через интерфейс командной строки было бы странно. В своей практике я не применял архетипы кроме как в ознакомительных целях.

Gradle. Gradle — аналог Maven, который появился чуть позже и считается более продвинутым, современным, стильным — модным — молодежным. Основное различие между ними — Gradle использует язык Groovy или Kotlin для конфигурации, а не XML, а также по-другому определяет жизненный цикл. Одно и то же приложение может одновременно иметь эквивалентные конфигурации сборок на Maven и Gradle. На сайте spring.io примеры одновременно содержат инструкции и для Maven, и для Gradle. При этом сам springframework начиная как минимум с версии 4 собирается с помощью Gradle. В работе же я встречал только Maven, если не считать одного приложения, которое потом перенесли на Maven для порядка и потому что Gradle билд сломался, а починить никто не сумел. По своему опыту могу только сказать, что Gradle очень плохо настраивается в окружении, где отсутствует или ограничен доступ в интернет. Не исключено, что при должной сноровке это возможно, но у кого она есть, эта сноровка. Я уверен, что в коммерческой разработке Maven ещё долго будет популярен благодаря старым проектам и наработанному специалистами опыту.

Заключение

В Mаven очень много нюансов и тонкостей, но в целом это очень стройная и эффективная технология и экосистема. Так или иначе, в мире Java разработки встречи с Maven не избежать. Надеюсь, что наиболее частые, полезные и хитрые сценарии я как-нибудь, да затронул.

Ответы на вопросы на собеседование Maven (часть 1).

Сборка (англ. assembly) — двоичный файл, содержащий исполняемый код программы или другой, подготовленный для использования информационный продукт.

Автоматизация сборки — этап написания скриптов или автоматизация широкого спектра задач применительно к ПО, применяемому разработчиками в их повседневной деятельности, включая такие действия, как:

  • Компиляция исходного кода в бинарный код
  • Сборка бинарного кода
  • Выполнение тестов
  • Разворачивание программы на производственной платформе
  • Написание сопроводительной документации или описание изменений новой версии
  • Что такое Maven? Как он работает?

Apache Maven — это фреймворк для автоматизации сборки проектов, компиляции, создания jar, создания дистрибутива программы, генерации документации. Если собирать большие проекты с командной строки, то команда для сборки будет очень длинной, поэтому её иногда записывают в bat/sh скрипт. Но такие скрипты зависят от платформы. Для того чтобы избавиться от этой зависимостии и упростить написание скрипта используют инструменты для сборки проекта.

Maven, обеспечивает декларативную, а не императивную сборку проекта. То есть, в файлах проекта pom.xml содержится его декларативное описание, а не отдельные команды. Все задачи по обработке файлов Maven выполняется через плагины.

  • Какие преимущества Maven?

Основные преимущества Maven:

  • Независимость от OS. Сборка проекта происходит в любой операционной системе. Файл проекта один и тот же.
  • Управление зависимостями. Редко какие проекты пишутся без использования сторонних библиотек(зависимостей). Эти сторонние библиотеки зачастую тоже в свою очередь используют библиотеки разных версий. Maven позволяет управлять такими сложными зависимостями. Что позволяет разрешать конфликты версий и в случае необходимости легко переходить на новые версии библиотек.
  • Возможна сборка из командной строки. Такое часто необходимо для автоматической сборки проекта на сервере (Continuous Integration).
  • Хорошая интеграция со средами разработки. Основные среды разработки на java легко открывают проекты которые собираются c помощью maven. При этом зачастую проект настраивать не нужно — он сразу готов к дальнейшей разработке.
  • Как следствие — если с проектом работают в разных средах разработки, то maven удобный способ хранения настроек. Настроечный файл среды разработки и для сборки один и тот же — меньше дублирования данных и соответственно ошибок.
  • Декларативное описание проекта.
  • Какие недостатки Maven?

Недостатки Maven:

  • Неочевидность. Если в Ant указывается команда на удаление — и удаляется файл, то в случае Maven надо всем сердцем довериться плагину и документации по нему.
  • При таком объёме необходимых знаний документации не так много, особенно по каким-то специальным моментам. Да и просто читать придётся много. Порог вхождения, если потребуется собирать даже не самое сложное приложение куда выше, чем у Ant.
  • Если нужно найти какой-то специальный плагин — это будет сделать непросто, плагинов много. И не факт, что найденный подойдёт на все 100% и будет работать без ошибок.
  • Нужен доступ в интернет (или придётся разворачивать собственный репозиторий, что трудоёмко)
  • Большие трудности, если проект не типовий.
  • Какими аспектами управляет Maven?

Вот основные аспекты, которыми позволяет управлять Maven:

  • Создание (Build)
  • Документирование (Documentation)
  • Отчёты (Reporting)
  • Зависимости (Dependencies)
  • Релизы (Releases)
  • SCM
  • Список рассылки (Mailing list)
  • Дистрибьюция (Distribution)
  • Как узнать какую версию Maven вы используете?

С помощью следующий команди:
mvn —version

  • Для чего создан Maven?

Основной целью Maven является предоставление разработчику:

  • Понятной модели для проектов, которая может быть использовано повторно и была бы проста в поддержании.
  • Плагины, которые могут взаимодействовать с этой моделью.

Структура и сожержание проекта Maven указывается в специальном xml-файле, который назывется Project Object Model (POM), который является базовым модулем всей системы.

  • Какая структура каталогов в Maven?

В Maven стандартная структура каталогов, благодаря ей отпадает необходимость прописывать пути к файлам проекта. В корневом каталоге проекта находится pom.xml и несколько текстовых файлов. Всё остальное хозяйство аккуратно разложено в подкаталогах. Главные из них — src и target. Однако, порядок сохраняется и вглубь:

  • Где вы хранятся файлы классов при компиляции проекта Maven?

Файлы классов хранятся в: $/target/classes/.

  • Что такое pom.xml?

pom.xml — это XML-файл, который содержит информацию о деталях проекта, и конфигурации используемых для создания проекта на Maven. Он всегда находится в базовом каталоге проекта. Этот файл также содержит задачи и плагины. Во время выполнения задач, Maven ищет файл pom.xml в базовой директории проекта. Он читает его и получает необходимую информацию, после чего выполняет задачи.

Корневой элемент , схема, которая облегчает редактирование и проверку, и версия pom.xml. Внутри тега project содержится основная и обязательная информация о проекте.

  • Какую информацию содержит pom.xml?

Среди информации которую содержит pom.xml мы можем выделить следующие:

  • Зависимости проекта (project dependencies)
  • Плагины (plugins)
  • Задачи/цели (goals)
  • Профиль создания (build profiles)
  • Версия проекта (project version)
  • Разработчики (developers)
  • Список рассылки (mailing list)
  • Что такое супер POM?

Все POM — файлы являются наследниками родительского pom.xml. Этот POM-файл называется Super POM и содержит значения, унаследованные по умолчанию.

  • Какие элементы необходимы для минимального POM?

Требуемые элементы для минимального POM ето корневий елемент, modelVersion, GroupID, artifactID и версия. Минимальный POM файл:

  • Что такое зависимости в Maven?

Зависимость (dependency) — это те библиотеки, которые непосредственно используются в вашем проекте для компиляции кода или его тестирования.

  • Что такое артефакт в Maven?

Артефакт (artefact) — это, по сути, любая библиотека, хранящаяся в репозитории (месте хранения). Это может быть какая-то зависимость или плагин. Обычно артефактом является JAR-файл, который хранится в репозитории Maven. Каждый артефакт содержит group ID, artifact ID и версию.

  • Что такое плагин в Maven?

Плагин (plugin) — это зависимости Maven’а, расширяющие его функционал.

  • Что такое задача в Maven?

Задача (goal) — это специальная задача, которая относится к сборке проекта и его управлению. Она может привязываться как к нескольким фазам, так и ни к одной. Задача, которая не привязана ни к одной фазе, может быть запущена вне фаз сборки с помощью прямого вызова.

  • Что такое архетип в Maven?

Архетип (archetype) — это некая стандартная компоновка файлов и каталогов в проектах различного рода (веб, swing-проекты и прочие). Другими словами, Maven знает, как обычно строятся проекты и в соответствии с архетипом создает структуру каталогов.

  • Что такое репозиторий в Maven?

Репозиторий (repository) — глобальное хранилище всех библиотек, доступных для Maven, это место где хранятся артефакты: jar файлы, pom-файлы, javadoc, исходники, плагины.

  • Какие типы репозитория существуют в Maven?

В Maven существуют три типы репозитория:

  • Локальный (local) репозиторий — это директория, которая хранится на нашем компьютере. Она создаётся в момент первого выполнения любой команды Maven. По умолчанию она расположена в /.m2/repository — персональная для каждого пользователя.
  • Центральный (central) репозиторий — это репозиториий, который обеспечивается сообществом Maven. Он содержит огромное количество часто используемых библиотек. Который расположен в http://repo1.maven.org/maven2/ и доступен на чтение для всех пользователей в интернете. Если Maven не может найти зависимости в локальном репозитории, то автоматически начинается поиск необходимых файлов в центральном репозитории
  • Удалённые (remote) репозиторий — иногда, Maven не может найти необходимые зависимости в центральном репозитории. В этом случае, процесс сборки прерывается и в консоль выводится сообщение об ошибке. Для того, чтобы предотвратить подобную ситуацию, в Maven предусмотрен механизм Удалённого репозитория, который является репозиторием, который определяется самим разработчиком. Там могут храниться все необходимые зависимости.
  • Какая команда установляет JAR-файл в локальное хранилище?

mvn install

  • Какой порядок поиска зависимостей Maven?

Когда мы выполняем собрку проекта в Maven, автоматически начинается поиск необходимых зависимостей в следующем порядке:

  1. Поиск зависимостей в локальном репозитории Если зависимости не обнаружены, происходит переход к шагу 2.
  2. Поиск зависимостей в центральном репозитории. Если они не обнаружены и удалённый репозиторий определён, то происходит переход к шагу 4.
  3. Если удалённый репозиторий не определён, то процесс сборки прекращается и выводится сообщение об ошибке.
  4. Поиск зависимостей на удалённом репозитории, если они найдены, то происходит их загрузка в локальный репозиторий, если нет — выводится сообщение об ошибке.
  • Какие два файла настройки есть в Maven, как они называются и где расположены?

В Maven, файлы настройки называются settings.xml, и они расположены в двох местах:

  • Каталог где установлен Maven: $M2_Home/conf/settings.xml
  • Домашняя директория пользователя: $/.m2/settings.xml
  • Что такое жизненный цикл сборки в Maven?

Жизненный цикл сборки(Lifecycle) — это чётко опредлённая последовательность фаз во время выполнения которых должын быть достигнуты определённые цели. Здесь фаза представляет собой стадию жизненного цикла.

  • Назовите основные фазы жизненного цикла сборки Maven?

Когда Maven начинает сборку проекта, он проходит через определённую последовательность фаз сборки, и выполняет определенные задачи, которые указаны в каждой из фаз.

В Maven есть следующие 3 стандартных жизненных цикла:

  • Очистка (clean) — очищает артефакты, созданные до сборки.
  • Сборка (default or build) — используется для создания приложения.
  • Создание сайта проекта (site) — генерирует документацию сайта для проекта.
  • Что делает команда mvn site?

mvn site — создает веб-сайт проекта.

  • Что делает команда mvn clean?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *