Многомодульные проекты maven

Со временем все программные проекты разрастаются. То, что начиналось как довольно жирный Hello World, весьма скоро обзаводится отдельным фронтендом, парочкой batch процессов, тремя видами RPC и общим кодом доступа к данным. И вот, в какой-то момент времени, возникает желание распилить этого монстра на неколько раздельных проектов, которые будут существовать независимо друг от друга.

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

Многомодульный проект проще всего представить себе как дерево — у него есть общий корень, который ничего не делает, а лишь описывает общие параметры, и листья, которые наследуют эти общие параметры. Листья могут иметь свои листья и так далее, пока память не кончится 🙂

Родительский модуль

Родительский модуль состоит из одного лишь pom файла, в котором описаны его дочерние модули:

В родительском pom есть две важные вещи — он должен определять <packaging/> как pom и должен перечислять дочерние модули. Всё остальное — как у обычного проекта: зависимости, плагины и так далее. Все настройки сборки, определённые в родительстком модуле, будут автоматически наследоваться дочерними.

Дочерний модуль

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

Дочерний модуль должен обязательно ссылаться на родительский модуль с помощью элемента <parent> Всё остальное — как у обычного maven проекта. В моём модуле будет один простой класс и тест к нему:

Обратите внимание, что в коде класса теста используется JUnit, зависимость от которого объявляется в родительском модуле.

Зависимости между дочерними модулями

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

Итак, теперь у нас есть два модуля и один зависит от другого. Такую зависимость можно описать в pom файле второго модуля:

Теперь maven знает, что перед сборкой второго модуля надо собрать первый и результаты сборки сделать доступными второму. Maven так же будет сам следить за изменениями в первом модуле и пересобирать второй по мере надобности. Стоит отметить, что если maven не может выявить зависимости между модулями, то он их будет собирать в том порядке, в котором они перечислены в элементе <modules/>.

Так второй модуль зависит от первого, это надо учесть и при сборке финального jar файла, поэтому я добавляю плагин maven-assembly-plugin, тем самым переопределяя унаследованные от родительского модуля настройки. Запуск готового приложения подтверждает корректность сборки:

Код примера доступен на github