Введение: что такое монорепозиторий и зачем он нужен Java-разработчику?
Представьте, что вы пишете большое Java-приложение: веб-сервис, библиотеку для работы с базами данных и отдельный модуль для логирования. Традиционно каждый компонент хранится в своём Git-репозитории. Но есть и другой подход — монорепозиторий (monorepo). Это стратегия, при которой весь код проекта (или даже нескольких связанных проектов) хранится в едином репозитории.
Для начинающих Java-разработчиков монорепозиторий может показаться необычным, но он даёт важные преимущества:
- Единая версия зависимостей — все модули используют одинаковые версии библиотек, что исключает конфликты.
- Упрощённый рефакторинг — изменение API в одном модуле сразу видно во всех зависимых модулях.
- Общие настройки — один файл конфигурации для линтера, форматирования и CI/CD.
- Лёгкий старт — не нужно настраивать несколько репозиториев для небольшого проекта.
В этой статье мы разберём, как организовать монорепозиторий на Java с использованием популярных инструментов сборки: Maven и Gradle. Вы узнаете, как структурировать папки, настраивать многомодульную сборку и избегать типичных ошибок.
Основная часть
1. Структура монорепозитория: от простого к сложному
Правильная структура папок — основа успешного монорепозитория. Вот рекомендуемый шаблон для Java-проекта:
my-monorepo/
├── build.gradle # Корневой файл сборки (для Gradle)
├── settings.gradle # Список модулей
├── pom.xml # Корневой POM (для Maven)
├── README.md
├── .gitignore
├── libs/ # Общие библиотеки
│ ├── common-utils/
│ └── logging-framework/
├── services/ # Микросервисы или приложения
│ ├── user-service/
│ └── payment-service/
└── tools/ # Утилиты и скрипты
└── code-generator/
Каждый модуль — это самостоятельный Java-проект со своим pom.xml или build.gradle. Корневые файлы конфигурации управляют зависимостями и версиями. Рассмотрим оба варианта подробнее.
2. Монорепозиторий с Maven: многомодульный проект
Maven поддерживает многомодульные проекты из коробки. Создайте корневой pom.xml с указанием модулей:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-monorepo</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<modules>
<module>libs/common-utils</module>
<module>services/user-service</module>
<module>services/payment-service</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
В модуле common-utils (папка libs/common-utils) создаём свой pom.xml, который ссылается на родительский проект:
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>my-monorepo</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>common-utils</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>
Теперь модуль user-service может использовать common-utils как внутреннюю зависимость:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common-utils</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
Сборка всего проекта одной командой:
mvn clean install
Maven автоматически соберёт модули в правильном порядке, учитывая зависимости.
3. Монорепозиторий с Gradle: гибкость и производительность
Gradle предлагает более гибкий синтаксис и лучшую производительность за счёт инкрементальной сборки. Начнём с корневого settings.gradle:
rootProject.name = 'my-monorepo'
include 'libs:common-utils'
include 'services:user-service'
include 'services:payment-service'
Корневой build.gradle определяет общие настройки:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0' apply false
id 'io.spring.dependency-management' version '1.1.4' apply false
}
subprojects {
apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
}
}
Модуль common-utils (папка libs/common-utils) содержит свой build.gradle:
dependencies {
implementation 'org.apache.commons:commons-lang3:3.14.0'
}
А модуль user-service подключает общую библиотеку:
plugins {
id 'org.springframework