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 и используемый профайл.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ