Модули в Java 9 — это одно из крупнейших изменений. На мой взгляд, оно одно из наиболее спорных, так как немного меняется подход к архитектуре приложения. Понятное дело, что старое корпоративное ПО никто не будет перелопачивать на модули, так как экономического эффекта от этого никакого не будет, а трудозатраты слишком высоки. Однако Jigsaw уже вошёл в состав Java 9, а это значит, что в скором времени каждый из нас сможет блеснуть (или наоборот) своими знаниями о нём на собеседованиях, для которых особенно будет полезно прочитать учебник по Java 8.
Понятное дело, что изучать что-либо новое лучше на каком-нибудь примере. Вы, например, можете изучить исходный код моего калькулятора с плагинами. Эту же статью я попытаюсь оформить в виде небольшой обучающей статьи.
Один простой модуль
Для начала напишем простенький модуль “sum”. Он у нас будет состоять из двух файлов: “Sum.java” и “module-info.java”.
Исходный код модуля согласно соглашению располагается в каталоге с именем модуля:
src/ru.urvanov.javaexamples.jigsawtutorialoperation/ru/urvanov/javaexamples/jigsawtutorialoperation/Sum.java”
1 2 3 4 5 6 7 8 9 10 11 |
package ru.urvanov.javaexamples.jigsawtutorial; public class Sum { public double calculate(double x, double y) { return x + y; } public static void main(String[] args) { System.out.println("Sum started!"); } } |
“src/ru.urvanov.javaexamples/jigsawtutorialoperation/module-info.java”
1 2 3 |
module ru.urvanov.javaexamples.jigsawtutorialoperation { } |
Модули компилируются по одному с помощью javac, но сначала мы создадим каталог для модуля:
1 |
$ mkdir -p mods/ru.urvanov.javaexamples.jigsawoperation |
Компилируем:
1 |
$ javac -d mods/ru.urvanov.javaexamples.jigsawtutorialoperation src/ru.urvanov.javaexamples.jigsawtutorialoperation/module-info.java src/ru.urvanov.javaexamples.jigsawtutorialoperation/ru/urvanov/javaexamples/jigsawtutorial/Sum.java |
Теперь мы можем запустить пример командой:
1 2 |
$ java --module-path mods -m ru.urvanov.javaexamples.jigsawtutorialoperation/ru.urvanov.javaexamples.jigsawtutorial.Sum Sum started! |
Использование класса из другого модуля
Добавим ещё один модуль и вызовем наш класс Sum из него.
“src/ru.urvanov.javaexamples.jigsawtutorialmain/module-info.java”
1 2 3 |
module ru.urvanov.javaexamples.jigsawtutorialmain { requires ru.urvanov.javaexamples.jigsawtutorialoperation; } |
Обратите внимание на requires, с помощью которого мы подключаем экспортируемые классы из модуля ru.urvanov.javaexamples.jigsawtutorialoperation. Нам также необходимо добавить строчку, экспортирующую класс Sum из этого модуля, для этого нам нужно поправить “module-info.java” в модуле ru.urvanov.javaexamples.jigsawtutorialoperation:
1 2 3 |
module ru.urvanov.javaexamples.jigsawtutorialoperation { exports ru.urvanov.javaexamples.jigsawtutorial; } |
“src/ru.urvanov.javaexamples.jigsawtutorialmain/ru/urvanov/javaexamples/jigsawtutorialmain/Main.java”
1 2 3 4 5 6 7 8 9 10 |
package ru.urvanov.javaexamples.jigsawtutorialmain; import ru.urvanov.javaexamples.jigsawtutorial.Sum; public class Main { public static void main(String[] args) { Sum sum = new Sum(); System.out.println("call sum = " + sum.calculate(1.0, 2.0)); } } |
Создаём каталоги для результирующих модулей:
1 |
$ mkdir -p mods/ru.urvanov.javaexamples.jigsawtutorialmain |
Компилируем:
1 |
$ javac --module-path mods -d mods/ru.urvanov.javaexamples.jigsawtutorialmain src/ru.urvanov.javaexamples.jigsawtutorialmain/module-info.java src/ru.urvanov.javaexamples.jigsawtutorialmain/ru/urvanov/javaexamples/jigsawtutorialmain/Main.java |
Теперь запустим наш модуль:
1 2 |
$ java --module-path mods -m ru.urvanov.javaexamples.jigsawtutorialmain/ru.urvanov.javaexamples.jigsawtutorialmain.Main call sum = 3.0 |
Упаковка
Модуль можно упаковать в модульный JAR-файл. Модульный JAR — это обычный JAR, но с “module-info.class” в своём корневом каталоге. Следующими командами мы создаём “ru.urvanov.javaexamples.jigsawtutorialmain.jar” и “ru.urvanov.javaexamples.jigsawtutorialoperation@1.0.jar”.
1 2 3 4 5 6 7 |
$ mkdir mlib $ jar --create --file=mlib/ru.urvanov.javaexamples.jigsawtutorialoperation@1.0.jar --module-version=1.0 -C mods/ru.urvanov.javaexamples.jigsawtutorialoperation . $ jar --create --file=mlib/ru.urvanov.javaexamples.jigsawtutorialmain.jar --main-class=ru.urvanov.javaexamples.jigsawtutorialmain.Main -C mods/ru.urvanov.javaexamples.jigsawtutorialmain . |
В этом примере модуль ru.urvanov.javaexamples.jigsawtutorialoperation упакован так, что он указывает, что его версия 1.0. Модуль ru.urvanov.javaexamples.jigsawtutorialmain упакован с указанием класса для запуска ru.urvanov.javaexamples.jigsawtutorialmain.Main . Теперь мы можем запустить модуль ru.urvanov.javaexamples.jigsawtutorialmain без указания класса для запуска:
1 2 |
$ java -p mlib -m ru.urvanov.javaexamples.jigsawtutorialmain call sum = 3.0 |
В команде выше используется клюс -p как альтернатива --module-path.
У утилиты jar есть также полезный ключ --describe-module, который выводит в консоль объявление модуля:
1 2 3 4 |
$ jar --describe-module --file=mlib/ru.urvanov.javaexamples.jigsawtutorialoperation\@1.0.jar ru.urvanov.javaexamples.jigsawtutorialoperation@1.0 jar:file:///C:/Users/fedya/MyData/Java/jigsaw-tutorial/mlib/ru.urvanov.javaexamples.jigsawtutorialoperation@1.0.jar/!module-info.class exports ru.urvanov.javaexamples.jigsawtutorial requires java.base mandated |
Сервисы
Сервисы позволяют уменьшить связь между модулями, использующими их, и модулями, предоставляющими их.
В качестве примера использования модуля рекомендую посмотреть мой проект калькулятора с плагинами.
Линковщик
Утилита jlink используется для объединения вместе набора модулей вместе с их зависимостями, чтобы создать пользовательский образ.
Следующая команда создаёт образ с модулем ru.urvanov.javaexamples.jigsawmain и его зависимостями:
1 |
$ jlink --module-path $JAVA_HOME/jmods:mlib --add-modules ru.urvanov.javaexamples.jigsawtutorialmain --output jigsawtutorialmain |
Значение для параметра --module-path это путь к каталогами с упакованными модулями. Для Windows нужно заменить разделитель пути «:» на «;».
Каталог $JAVA_HOME/jmods содержит java.base.jmod и другие стандартные модули JDK.
Каталог “mlib” содержит jar-файлы и сам модуль ru.urvanov.javaexamples.jigsawtutorialmain.