JavaRush /Курсы /JAVA 25 SELF /Сборка многомодульных проектов: Maven, Gradle, IDEA

Сборка многомодульных проектов: Maven, Gradle, IDEA

JAVA 25 SELF
60 уровень , 4 лекция
Открыта

1. Сборка модульных проектов: базовые принципы

Компилятор и модульный путь (module-path)

До появления модулей всё приложение компилировалось и запускалось с помощью так называемого classpath — просто списка каталогов и JAR-файлов, в которых Java искала классы. В модульной системе появился новый игрок — module-path. Теперь компилятор и JVM должны знать не только, где лежат классы, но и к каким модулям они принадлежат, какие зависимости у них есть, и какие пакеты экспортируются.

Ключевой момент:

  • Для модульных проектов используйте --module-path вместо -classpath.
  • Компилятор и JVM должны видеть все модули, которые нужны вашему приложению (и их зависимости).

Пример: ручная компиляция модулей

Предположим, у вас есть два модуля: core и app, где app зависит от core.

Структура каталогов:

project-root/
  core/
    src/
      main/
        java/
          module-info.java
          com/example/core/...
  app/
    src/
      main/
        java/
          module-info.java
          com/example/app/...

Ручная компиляция (демонстрация):

# Сначала компилируем core
javac -d out/core core/src/main/java/module-info.java core/src/main/java/com/example/core/*.java

# Затем app, указав module-path на core
javac --module-path out/core -d out/app app/src/main/java/module-info.java app/src/main/java/com/example/app/*.java

Запуск:

java --module-path out/core:out/app -m app/com.example.app.Main

В реальных проектах вручную этим заниматься не нужно — используйте Maven/Gradle или IDE.

2. Maven: сборка многомодульных проектов

Структура многомодульного проекта в Maven

Maven давно поддерживает структуру с несколькими модулями (submodules). Теперь, с появлением модульной системы Java, эти «модули» Maven часто совпадают с модулями Java, но не всегда: Maven-модуль — это просто подпроект, а Java-модуль — это то, что описано в module-info.java. Обычно один Maven-модуль = один Java-модуль.

Типичная структура:

myproject/
  pom.xml                # Parent POM
  core/
    pom.xml              # Модуль core
    src/main/java/
      module-info.java
      com/example/core/...
  app/
    pom.xml              # Модуль app
    src/main/java/
      module-info.java
      com/example/app/...

Пример parent POM (myproject/pom.xml):

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>myproject</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <modules>
    <module>core</module>
    <module>app</module>
  </modules>
</project>

Пример POM для модуля core (core/pom.xml):

<project>
  <parent>
    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>core</artifactId>
  <dependencies>
    <!-- Здесь могут быть зависимости, например, на другие модули или сторонние библиотеки -->
  </dependencies>
</project>

Пример POM для модуля app (app/pom.xml):

<project>
  <parent>
    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>app</artifactId>
  <dependencies>
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>core</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>

Важно:

  • Если в app требуется core, в module-info.java модуля app должно быть requires core;
  • Maven сам соберёт зависимости, если правильно прописаны <dependency> и <module>.

Как Maven учитывает module-info.java

  • Maven автоматически компилирует module-info.java вместе с остальными классами.
  • Если у вас есть модульные зависимости, Maven добавит их в module-path при компиляции и запуске.
  • Если вы используете старые плагины или Java ниже 9 — модульная система работать не будет.

Запуск модульного приложения через Maven

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.10.1</version>
      <configuration>
        <release>21</release> <!-- или ваша версия Java -->
      </configuration>
    </plugin>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <version>3.1.0</version>
      <configuration>
        <mainClass>com.example.app.Main</mainClass>
        <commandlineArgs></commandlineArgs>
      </configuration>
    </plugin>
  </plugins>
</build>
mvn clean install
mvn -pl app exec:java

Типичные ошибки при работе с Maven и модулями

Ошибка: "module not found". Не указали правильный module-path или не прописан <dependency> для зависимого артефакта.

Дублирование имён модулей. В проекте не должно быть двух модулей с одинаковыми именами (например, два module core).

Отсутствие export/requires. Если забыли экспортировать пакет (exports) или объявить зависимость (requires), будет ошибка компиляции.

Смешивание classpath и module-path. Не используйте устаревшие плагины/настройки, не поддерживающие модули: это ведёт к непредсказуемым ошибкам.

3. Gradle: сборка многомодульных проектов

Структура проекта на Gradle

myproject/
  settings.gradle
  build.gradle
  core/
    build.gradle
    src/main/java/module-info.java
    src/main/java/com/example/core/...
  app/
    build.gradle
    src/main/java/module-info.java
    src/main/java/com/example/app/...

settings.gradle

rootProject.name = 'myproject'
include 'core', 'app'

build.gradle (корневой)

subprojects {
    apply plugin: 'java'

    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(21) // или ваша версия Java
        }
    }

    repositories {
        mavenCentral()
    }
}

build.gradle для core

plugins {
    id 'java'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

build.gradle для app

plugins {
    id 'java'
    id 'application'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

dependencies {
    implementation project(':core')
}

application {
    mainModule = 'app' // Имя вашего Java-модуля
    mainClass = 'com.example.app.Main'
}

Сборка и запуск

./gradlew build
./gradlew :app:run

Gradle сам определяет module-path, если находит module-info.java. Если что-то не работает — проверьте, что используете свежую версию Gradle и плагинов.

4. IntelliJ IDEA: создание и настройка модульного проекта

Создание модульного проекта

  • File → New → Project → Java → включите «Create module-info.java».
  • Для многомодульного проекта: File → New → Module — добавляйте новые модули в проект.
  • Если используете Maven/Gradle — просто импортируйте проект по pom.xml или build.gradle.

Структура в IDEA

  • В Project View каждый модуль отображается как отдельная ветка.
  • В каждом модуле — свой module-info.java, свои исходники.
  • IDEA подсказывает, какие модули экспортируют/требуют какие пакеты (exports/requires).
  • Если забыли экспортировать пакет или объявить зависимость — IDEA подсветит ошибку.

Проверка module-path, запуск main-класса

  • В Run/Debug Configurations укажите:
    • Main class (например, com.example.app.Main)
    • Module (например, app)
  • IDEA сама разберётся с module-path.
  • Если запускаете через Maven/Gradle — используйте соответствующие конфигурации (например, app [run]).

Импорт сторонних модулей и библиотек

  • Для работы с внешними библиотеками (например, requires java.sql; или сторонние JAR'ы) — добавьте зависимость через Maven/Gradle.
  • Если библиотека не модульная (нет module-info.java), она будет автоматически добавлена в «unnamed module» (это нормально для большинства библиотек).

5. Практика: создание простого многомодульного проекта

Шаг 1. Создаём структуру проекта

myproject/
  core/
    src/main/java/module-info.java
    src/main/java/com/example/core/HelloService.java
  app/
    src/main/java/module-info.java
    src/main/java/com/example/app/Main.java

HelloService.java (core):

package com.example.core;

public class HelloService {
    public String getHello() {
        return "Привет от core-модуля!";
    }
}

module-info.java (core):

module core {
    exports com.example.core;
}

Main.java (app):

package com.example.app;

import com.example.core.HelloService;

public class Main {
    public static void main(String[] args) {
        HelloService service = new HelloService();
        System.out.println(service.getHello());
    }
}

module-info.java (app):

module app {
    requires core;
}

Шаг 2. Сборка и запуск через Maven

В корне проекта создаём parent pom.xml и два подпроекта (core/pom.xml, app/pom.xml) как выше. В app/pom.xml добавляем зависимость на core.

mvn clean install
mvn -pl app exec:java

Шаг 3. Сборка и запуск через Gradle

Создаём settings.gradle, корневой build.gradle, и по одному для каждого модуля. В app/build.gradle прописываем зависимость на core и mainClass.

./gradlew build
./gradlew :app:run

Шаг 4. Импорт и запуск в IntelliJ IDEA

  • Открываем корень проекта через File → Open.
  • IDEA распознает структуру Maven/Gradle, создаст модули.
  • В каждом модуле можно открыть module-info.java, IDEA покажет связи между модулями.
  • Запускаем Main.java через контекстное меню («Run Main.main()») — IDEA сама выставит module-path.

6. Типичные ошибки при сборке модульных проектов

Ошибка №1: Неправильный module-path. Если при запуске или компиляции появляется сообщение вроде «module not found» или «package is not visible», скорее всего, вы не указали корректный module-path или забыли добавить зависимость в pom.xml/build.gradle.

Ошибка №2: Дублирование имён модулей. В проекте не должно быть двух модулей с одинаковым именем (например, два module core). Это приводит к ошибке компиляции.

Ошибка №3: Неэкспортированный пакет. Если класс находится в пакете, который не экспортируется через exports в module-info.java, то он будет недоступен другим модулям, даже если public. Возникнет ошибка компиляции при попытке использовать такой класс.

Ошибка №4: Необъявлённый requires. Если модуль использует классы из другого модуля, но не указал requires в module-info.java, компилятор выдаст ошибку.

Ошибка №5: Несовместимость с внешними библиотеками. Нематчинг модулей и библиотек без module-info.java (они попадают в «unnamed module») обычно не мешает, но в некоторых конфигурациях может потребоваться дополнительная настройка.

Ошибка №6: Запуск не из того модуля. В конфигурации запуска IDEA или Maven/Gradle указан неверный main-класс или модуль — приложение не стартует. Проверьте Main, mainModule/module и используемый профайл.

1
Задача
JAVA 25 SELF, 60 уровень, 4 лекция
Недоступна
Строительство крепости многомодульного проекта 🏰
Строительство крепости многомодульного проекта 🏰
1
Задача
JAVA 25 SELF, 60 уровень, 4 лекция
Недоступна
Запуск сердца приложения через Maven ✨
Запуск сердца приложения через Maven ✨
1
Опрос
Модули и структура проекта, 60 уровень, 4 лекция
Недоступен
Модули и структура проекта
Модули и структура проекта
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ