Монорепозиторий с Java: организация кода для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: что такое монорепозиторий и зачем он нужен 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                

Блоги

Рекомендаций по книгам