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                # Батьківський 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/...

Приклад батьківського 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

У корені проєкту створюємо батьківський 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
Опитування
Модулі та структура проєкту, рівень 60, лекція 4
Недоступний
Модулі та структура проєкту
Модулі та структура проєкту
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ