Модульная система Java Platform (JPMS) обеспечивает большую надежность, лучшее разделение проблем и более сильную инкапсуляцию приложений Java. Однако это не инструмент сборки, поэтому ему не хватает возможности автоматического управления зависимостями проекта.
Конечно, мы можем задаться вопросом, можем ли мы использовать хорошо зарекомендовавшие себя инструменты сборки, такие какMavenилиGradle , в модульных приложениях.
На самом деле, мы можем! В этом уроке мы узнаем, как создать многомодульное приложение Maven с использованием модулей Java .
2. Инкапсуляция модулей Maven в модули Java
Поскольку модульность и управление зависимостями не являются взаимоисключающими понятиями в Java, мы можем легко интегрировать JPMS , например, с Maven, таким образом используя лучшее из обоих миров.
В стандартном многомодульном проекте Maven мы добавляем один или несколько дочерних модулей Maven, помещая их в корневую папку проекта и объявляя их в родительском POM в разделе .
В свою очередь, мы редактируем POM каждого дочернего модуля и указываем его зависимости с помощью стандартных координат < groupId> , < artifactId> и < version> .
Механизм reactor в Maven, отвечающий за обработку многомодульных проектов, заботится о построении всего проекта в правильном порядке.
В этом случае мы будем в основном использовать ту же методологию проектирования, но с одним тонким, но фундаментальным вариантом: мы обернем каждый модуль Maven в модуль Java, добавив к нему файл дескриптора модуля , module-info.java .
3. Родительский модуль Maven
Чтобы продемонстрировать, как модульность и управление зависимостями отлично работают вместе, мы создадим базовый демонстрационный многомодульный проект Maven, функциональность которого будет сужена до простого извлечения некоторых объектов домена из слоя персистентности .
Чтобы код был простым, мы будем использовать простую Карту в качестве базовой структуры данных для хранения объектов домена. Конечно, в дальнейшем мы можем легко переключиться на полноценную реляционную базу данных.
Давайте начнем с определения родительского модуля Maven. Для этого давайте создадим корневой каталог проекта с именем, например, multi module maven project (но это может быть что угодно другое), и добавим в него родительский pom.xml файл:
Есть несколько деталей, которые стоит отметить в определении родительского ПОМ.
Во-первых, поскольку мы используем Java 11, нам понадобится по крайней мере Maven 3.5.0 в нашей системе,поскольку Maven поддерживает Java 9 и выше начиная с этой версии .
Как мы видим, модуль Entity не имеет никаких зависимостей от других модулей и не требует дополнительных артефактов Maven, поскольку он включает только класс User .
Теперь нам нужно инкапсулировать модуль Maven в модуль Java . Чтобы достичь этого, давайте просто разместим следующий файл дескриптора модуля ( module-info.java ) в каталоге entity module/src/main/java :
Наконец, давайте добавим дочерний модуль Maven в родительский POM:
entitymodule
4.2. Модуль daomodule Maven
Давайте создадим новый модуль Maven, который будет содержать простой интерфейс. Это удобно для определения абстрактного контракта для извлечения универсальных типов из уровня сохраняемости.
На самом деле, есть очень веская причина для размещения этого интерфейса в отдельном модуле Java. Таким образом, у нас есть абстрактный, сильно разобщенный контракт, который легко использовать в разных контекстах. По сути, это альтернативная реализация принципа инверсии зависимостей , которая обеспечивает более гибкую конструкцию.
Поэтому давайте создадим структуру каталогов dao module/src/main/java/com/baeldung/dao в корневом каталоге проекта и добавим в нее интерфейс Dao :
public interface Dao {
Optional findById(int id);
List findAll();
}
Новый модуль также не требует других модулей или артефактов, поэтому мы просто завернем его в модуль Java. Давайте создадим дескриптор модуля в каталоге dao module/src/main/java :
Наконец, давайте добавим модуль в родительский POM:
entitymoduledaomodule
4.3. Модуль Maven userdaomodule
Далее давайте определим модуль Maven, который содержит реализацию интерфейса Dao .
В корневом каталоге проекта давайте создадим структуру каталогов userdaomodule/src/main/java/com/baeldung/userdao и добавим в нее следующий класс UserDao :
public class UserDao implements Dao {
private final Map users;
// standard constructor
@Override
public Optional findById(int id) {
return Optional.ofNullable(users.get(id));
}
@Override
public List findAll() {
return new ArrayList<>(users.values());
}
}
Проще говоря, UserDao класс предоставляет базовый API, который позволяет нам извлекать Пользователь объекты из слоя сохранения.
Чтобы все было просто, мы использовали Map в качестве резервной структуры данных для сохранения объектов домена. Конечно, можно обеспечить более тщательную реализацию, использующую, например, entitymanager Hibernate .
В этом случае все немного по-другому, так как модуль userdao требует модуля e nity и модуля dao модулей. Вот почему мы добавили их в качестве зависимостей в pom.xml файл.
Нам все еще нужно инкапсулировать этот модуль Maven в модуль Java. Итак, давайте добавим следующий дескриптор модуля в каталог userdao module/src/main/java :
Наконец, нам нужно добавить этот новый модуль в родительский POM:
entitymoduledaomoduleuserdaomodule
С точки зрения высокого уровня легко увидеть, что |/pom.xmlфайл и дескриптор модуля играют разные роли. Тем не менее, они прекрасно дополняют друг друга.
Допустим, нам нужно обновить версии артефактов e n tity module и dao module Maven. Мы можем легко сделать это без необходимости изменять зависимости в дескрипторе модуля. Maven позаботится о том, чтобы включить нужные артефакты для нас.
Аналогично, мы можем изменить реализацию службы, которую предоставляет модуль, изменив директиву “provides..with” в дескрипторе модуля.
Мы много выигрываем, когда используем модули Maven и Java вместе. Первый обеспечивает функциональность автоматического централизованного управления зависимостями, в то время как второй обеспечивает внутренние преимущества модульности .
4.4. Основной модуль приложения Модуль Maven
Кроме того, нам нужно определить модуль Maven, содержащий основной класс проекта.
Как и раньше, давайте создадим main app module/src/main/java/main app структуру каталогов в корневом каталоге и добавим в нее следующий Application класс:
public class Application {
public static void main(String[] args) {
Map users = new HashMap<>();
users.put(1, new User("Julie"));
users.put(2, new User("David"));
Dao userDao = new UserDao(users);
userDao.findAll().forEach(System.out::println);
}
}
Метод Application класса main() довольно прост. Во-первых, он заполняет HashMap несколькими объектами User . Затем он использует экземпляр UserDao для извлечения их с карты , а затем отображает их на консоли.
Кроме того, нам также необходимо определить модуля pom.xml файл:
Зависимости модуля довольно понятны. Итак, нам просто нужно поместить модуль внутри модуля Java. Поэтому в структуре каталогов main app module/src/main/java давайте включим дескриптор модуля:
Наконец, давайте добавим этот модуль в родительский POM:
entitymoduledaomoduleuserdaomodulemainappmodule
Поскольку все дочерние модули Maven уже установлены и аккуратно инкапсулированы в модули Java, вот как выглядит структура проекта:
multimodulemavenproject (the root directory)
pom.xml
|-- entitymodule
|-- src
|-- main
| -- java
module-info.java
|-- com
|-- baeldung
|-- entity
User.class
pom.xml
|-- daomodule
|-- src
|-- main
| -- java
module-info.java
|-- com
|-- baeldung
|-- dao
Dao.class
pom.xml
|-- userdaomodule
|-- src
|-- main
| -- java
module-info.java
|-- com
|-- baeldung
|-- userdao
UserDao.class
pom.xml
|-- mainappmodule
|-- src
|-- main
| -- java
module-info.java
|-- com
|-- baeldung
|-- mainapp
Application.class
pom.xml
5. Запуск приложения
Наконец, давайте запустим приложение либо из нашей IDE, либо из консоли.
Как и следовало ожидать, при запуске приложения мы должны увидеть несколько объектов User , распечатанных на консоли:
User{name=Julie}
User{name=David}
6. Заключение
В этом уроке мы прагматично узнали как заставить Maven и JPMS работать бок о бок при разработке базового многомодульного проекта Maven, использующего модули Java .
Как обычно, все примеры кода, показанные в этом руководстве, доступны на GitHub .