Pull to refresh

Maven — зачем?

Reading time7 min
Views83K
На просторах сети вообще и хабра в частности мне доселось видеть не один топик посвящённый Maven. И везде, где было обсуждение, возникали вопросы вида:
  • Что даёт его использование в проекте типа X?
  • Чем он лучше Ant/Make/sh?
  • А что делать если я хочу использовать в проекте antlr/JAX-WS/XDoclet?

Я полагаю, что все эти вопросы происходят из незнания что на свете есть гугл недостаточного понимания что такое Maven и какой подход к решению задач build management он предлагает. Что в свою очередь растёт из недостаточного внимания, которое авторы статей уделяют идеям стоящим за xml-файлами и завораживающими консольными командами.


Мне очень важным кажется понимание того, что когда говорят Maven подразумевают 3 достаточно слабо связанные вещи:
  • POM. Project object model. Модель проекта — в ней описано из чего проект состоит и как устроен его жизненный цикл.
  • Репозитории артефактов. Места хранения продуктов сборки программных модулей вместе с метаданными.
  • Утилиту mvn и плагины к ней. Собственно инструмент сборки проектов управления жизненным циклом модулей.

Давайте рассмотрим каждую в отдельности, чтобы понять как их можно использовать вместе.

POM


Это общая модель проектов. В ней описываются такие общие характеристики как имя, версия, авторы и их контактная информация, VCS проекта и вообще связанные с ним сетевые ресурсы, тип проекта (например библиотека или web-модуль, в оригинальной терминологии называется packaging, хотя влияет не только на тип получаемого артефакта), связи с другими проектами, используемые при сборке плагины и описания способа их задействования. Мне кажутся особенно важными два компонента этой модели.

Связи с другими модулями

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

Зависимость, эта связь говорит, что для некоторых фаз жизненного цикла нашего модуля, требуются некоторые артефакты модулей-зависимостей (абстрактно получилось — аж самому страшно). Что конкретно и на какой фазе жизненного цикла требуется определяется так называемой областью действия зависимости. Maven понимает несколько предопределённых областей действия и позволяет добавлять свои. В качестве примера ограничусь одной областью действия: compile — она говорит, что бинарные сборки зависимости требуются на этапе компиляции, выполнения тестов и во время выполнения.

Включение — говорит, что связанный модуль является неотъемлемой частью нашего модуля. Для прохождения нашим модулем некоторой фазы жизненного цикла, входящий в него также должен пройти эту фазу. Классический пример enterprise-модуль, включающий в себя web-модуль, пакет с EJB и общую библиотеку. Очевидно, что его сборка требует сборки каждого из включаемых модулей.

Наследование. Такая связь подразумевает перенос на наследника части модели предка. Правила переноса несколько запутаны, но в основном действует принцип — значение параметра модели предка становится умолчанием для модели потомка. Пример из моей практики: был создан модуль, устанавливающий версию JDK для компиляции проектов, внутренние репозитарии для результатов, набор правил для поверки соответствия исходников стандарту кодирования, он должен был использоваться (а кое-где и действительно использовался ;) ) как родитель для всех разрабатываемых в рамках проекта модулей.

Описание используемых при сборке плагинов

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

Этот элемент несколько чужд общей идеи POM — он несёт не декларативное описание модуля, а инструкции по его сборке конкретным инструментом.

Итоги
  1. POM — эта общая, унифицированая модель описания программных модулей.
  2. Она поддерживает хранение не только аттрибутов отдельных модулей но и высокоуровневых связей между ними.
  3. Также она несёт информацию об инструментах, необходимых для поддержки жизненного цикла модуля.

Репозитории артефактов


Репозитории артефактов являются выделенными хранилищами результатов сборки, устроенными так, чтобы упростить поиск нужного артефакта (по имени, версии, типу артефакта). Они позволяют группе разработчиков пользоваться результатами работы друг друга без необходимости иметь копии исходных кодов их модулей и выполнять сборку дерева зависимостей с 0. Maven-совместимые репозитарии стали стандартом де факто публикации результатов различных открытых проектов.

Нужно заметить, что pom-файлы, содержащие модель проекта, также являются артефактами и могут хранится в репозитариях вместе со всеми (на самом деле по крайней мере урезанные их версии, содержащие только идентификацию модуля и зависимости, хранятся всегда). Таким образом репозитарий является в том числе источником информации (как миннимум достаточной для дистрибуции) о хранимых в нём модулях.

Итак, какие бонусы они нам дают:
  1. Структурированное хранение артефактов, их каталогизация.
  2. Повторное использование артефактов.

Утилита управления жизненным циклом


Название получилось достаточно пафосное, однако оно вполне соответствует высокой миссии и сложности предмета.

Прежде чем погрузиться в её функции, необходимо немного познакомится с теорией организации жизненного цикла модуля в Maven. Жизненным циклом называется вся совокупность операций над модулем от инициализации сборки до развёртывания. В процессе прохождения жизненного цикла выполняются определённые операции над модулем, формируются некоторые артефакты. Жизненный цикл разделён на фазы. Каждая фаза подразумевает перевод модуля в новое состояние в результате её прохождения и появление новых артефактов. Каждая предыдущая фаза подготовливает основу для последующей. Список фаз является по сути частью POM, но глобальной, общей для всех модулей. Поный список приводить бессмысленно, но для примера приведу несколько фаз (достаточно интуитивно названных, на мой взгляд :) ) в порядке их следования: compile,… test,… deploy.

В рамках каждой фазы выполняется некоторый набор целей в зависимости от модели конкретного модуля. Цель является конкретной операцией над исходными кодами и/или артефактами.

Теперь к самой утилите. Она отвечает за реализацию жизненного цикла на основании модели проекта. Состоит из двух основных компонентов:
  1. Во-первых из совсем маленького ядра, в котором описаны (захардкожены, как говорит простой народ) базовые принципы устройства проектов, цели по умолчанию для фаз стандартных типов проектов, рабочая среда для плагинов (интерфейсы доступа к моделям, репозитариям, ФС, настройкам и т.п.).
  2. Во-вторых из плагинов. Они собственно содержат код, выполняющий цели. Практически вся внешняя функциональность mvn реализуется ими. Именно они генерируют, компилируют, тестируют, пакуют и т.д. и т.п.

Общение с этой утилитой построено предельно просто: вы говорите до какой кондиции фазы нужно довести клиента модуль и она это делает. Вся сложность формулировки и выполнения задач по достижению цели остаётся на совести разработчиков плагинов (ну хорошо, немного остаётся на разработчика модели). Например говорим compile и нам компилируют, причём не только то, что вылезло из VCS но и генерируют необходимое например wsimport'ом и результаты тоже компилируют.

Также можно попросить выполнить отдельную задачу конкретного плагина. Например есть плагин для генерации Eclipse-проектов, задача «сгенерировать проект» которого по умолчанию не привязывается ни к одной фазе, а вызывается заинтересованными лицами вручную.

Ещё одной крайне интересной функцией mvn является создание заготовки проекта на основе архетипа. Архетип — обобщённый шаблон проекта, традиционно концентрирующийся на его структуре и используемых плагинах. Например есть стандартные архетипы java-библиотеки, web-модуля, и нестандартные, например grails приложение. Важно понимать отличие архетипа от типа проекта. Архетип — только шаблон начальной структуры и отдельных частей проекта, после создания проекта никакой информации о его архетипе не остаётся. Тип проекта — наоборот, часть модели, которая используется на протяжении всего жизненного цикла.

Что получается в сумме


Итак, мы выделили три столпа Maven. Что-же они дают нам вместе?

  • Концентрирование информации о модуле в одном месте и в одном формате. Не всё тут гладко, но многие IDE могут импортировать проекты из POM, большинство серверов автокомпиляции (continuous integration, как говорят адепты XP) также могут использовать их добавлении проекта.
  • Единая система идентификации модулей. Очень просто и очень важно. У нас нет теперь обозначений типа багфикс-ветка нашего-супер-проекта, собранная в 23 часа в прошлую субботу.
  • Один инструмент. Хотя это, прямо скажем, не уникальная фича Maven. Не удержусь и повторю прописную истину: проект должен собираться стандартными и переносимыми средствами. Сборка любимой IDE Первого Разработчика Проекта — путь в ад.
  • Автоматическое управление зависимостями. Связывание исходного кода проекта с бинарными сборками чего-то, очень невесёлая практика. Особо надо отметить трудности с поддержкой репозитариев исходников (сколько магнитных лент занимает бэкап вашего svn?)) ). Изобретения велосипеда в виде своих репозитариев или скриптов подтаскивающих исходнки зависимостей тоже не лучшее решение в эпоху, когда космические корабли бороздят просторы вселенной.
  • Повторное использование решений, связанных с устройством и процедурой сборки проектов. Благодаря наследованию и включению проектов мы можем многократно использовать однажды разработанные модели проектов, настройки, связанные с инфраструктурой и инструментарием принятыми в нашей компании. Использование архетипов позволяет автоматизировать этап создания новых проектов, съэкономить время на подготовке структуры проекта и минимизировать ошибки в использовании внешних моделей.
  • Готовое средство для управления результатами работы и простота их последующего использования. Настраиваем инфраструктуру подобающим образом и каждый билд оседает в нужном месте и доступен для последующего использования. Нужно проверить работоспособность разных компоновок версий/веток модулей большого проекта? Просто правим зависимости в POM.

Заключение


Что-то я местами отклонился от центрального вопроса и вплотную занялся вопросом «как», ну да ладно…

Из всей информации, приведённой выше, можно сделать простой, но почему-то весьма редкий вывод. Maven — не утилита для сборки Java-приложений. Maven — фреймворк для автоматизации большого спектра задач при поддержке проекта. Он никак не связан с языком и платформой, более того он совершенно не обязан что-либо собирать. Вы с помощью описания моделей или написания плагинов превращаете его в тот или иной инструмент. Да, принятая в нём по модель по умолчанию — сборка Java-модулей, но это лишь умолчания…

Надеюсь, что после прочтения топика каждый может уверенно ответить на вопросы, приведённые в начале ;)

P.S. Ещё я с интересом узнаю о вашем опыте нестандартного применения Maven. Есть идея в будующем создать пост с примерами интересных и необычных use case'ов для него.
Tags:
Hubs:
Total votes 5: ↑3 and ↓2+1
Comments3

Articles