Этап 4 - Многомодульные проекты: архитектура больших Java-систем
Один модуль удобен, пока приложение маленькое. Но в большом backend-проекте быстро появляются DTO для API, бизнес-логика, работа с базой данных, веб-контроллеры, общие утилиты и иногда сгенерированные клиенты. Если все это лежит в одном модуле, проект становится трудно читать, тестировать и переиспользовать.
Многомодульный проект делит одну логическую систему на несколько модулей сборки. У каждого модуля есть свой артефакт и свои зависимости, а корневой проект координирует сборку целиком.

Когда один модуль уже мешает
Представь сервис заказов. В нем есть HTTP-контроллеры, бизнес-правила, JPA-репозитории, DTO и общие классы. Если все находится в одном модуле, разработчик может случайно вызвать controller из service или использовать web-класс внутри repository. Код начинает зависеть от всего подряд.
Модули помогают явно показать границы. web отвечает за HTTP. service отвечает за бизнес-логику. repository отвечает за работу с базой. api может хранить DTO и контракты. common хранит действительно общие классы, но туда нельзя складывать все подряд.
В Maven корневой pom.xml часто имеет тип упаковки pom и секцию <modules>. В этой секции перечисляют дочерние модули. Корневой файл также может задавать общие свойства, версии зависимостей и настройки плагинов, которые наследуют дочерние модули.
Aggregator - это проект, который перечисляет модули и запускает их сборку вместе. Parent - это проект, от которого модули наследуют настройки. В реальных Maven-проектах один корневой POM часто выполняет обе роли, но полезно понимать разницу.
Зависимости между модулями должны идти в одну сторону. web может зависеть от service, а service может зависеть от repository. Но repository не должен зависеть от web. Если появляется цикл, границы модулей выбраны неправильно.
Последовательность шагов
- Корневой проект объявляет список модулей.
- Каждый модуль описывает свои зависимости.
- Общие версии и настройки выносятся в корневой файл.
- Maven или Gradle определяет порядок сборки.
- Сначала собираются нижние модули, затем модули, которые от них зависят.
Главная картинка такая: верхний слой вызывает нижний, но нижний слой не знает о верхнем.
Конкретный пример
project
|-- api
|-- service
|-- common
|-- repository
`-- web
Этот пример показывает не папки ради папок, а разделение ответственности. Если нужно изменить HTTP endpoint, ты идешь в web. Если меняется бизнес-правило, ты идешь в service. Если меняется SQL или JPA-запрос, ты идешь в repository. Если несколько модулей используют один класс, он может лежать в common.
Пример корневого Maven-файла:
<project>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>api</module>
<module>service</module>
<module>repository</module>
<module>web</module>
</modules>
</project>
Полезная таблица
| Понятие | Значение |
|---|---|
| Parent | Родительский проект, от которого модули наследуют настройки. |
| Aggregator | Корневой проект, который перечисляет модули и запускает общую сборку. |
| Module dependency | Зависимость одного модуля от классов или артефакта другого модуля. |
| Reactor build | Maven-сборка связанных модулей в правильном порядке. |
Где это встречается в работе
Модули нужны для реальных границ ответственности, а не ради красивой структуры папок. Хорошие модули уменьшают связанность кода. Плохие модули только замедляют сборку и заставляют разработчиков прыгать между файлами.
Частые ошибки
- Делать модуль для каждой маленькой папки.
- Создавать циклические зависимости между модулями.
- Складывать весь общий код в
common, пока он не превращается в свалку. - Путать parent и aggregator и не понимать, откуда модуль наследует настройки.
Чеклист понимания
- Я могу объяснить, зачем проект делят на модули.
- Я понимаю, почему зависимости должны идти в одну сторону.
- Я могу прочитать секцию
<modules>в Maven. - Я понимаю, какую роль выполняют
web,serviceиrepository.
Вопросы для самопроверки
- Почему
repositoryне должен зависеть отweb? - Чем parent отличается от aggregator?
- Когда модуль
commonстановится проблемой?
Практика перед следующим уроком
Нарисуйте проект из четырех модулей: web, service, repository и common. Проведите стрелки только туда, куда код действительно может зависеть. Если у вас появилась стрелка от repository к web, объясните, какое архитектурное правило нарушено.