Что такое модуль в java

Модульность

Создание модуля

Что такое модуль в java. Смотреть фото Что такое модуль в java. Смотреть картинку Что такое модуль в java. Картинка про Что такое модуль в java. Фото Что такое модуль в java

До Java 9 было несколько уровней инкапсуляции функционала. Первый уровень представлял класс, в котором мы могли определить переменные и методы с различным уровнем доступа. Следующий уровень представлял пакет, который, в свою очередь, представлял коллекцию классов. Однако со временем этих уровней оказалось недостаточно. И модуль стал следующим уровнем инкапсуляции, который объединял несколько пакетов.

Модуль состоит из группы пакетов. Также модуль включает список все пакетов, которые входят в модуль, и список всех модулей, от которых зависит данный модуль. Дополнительно (но необязательно) он может включать файлы ресурсов или файлы нативных библиотек.

В качестве названия модуля может использоваться произвольный идентификатор из алфавитно-цифровых символов и знаков подчеркивания. Но рекомендуется, чтобы название модуля соответствовало названию, которого начинаются пакеты этого модуля.

В каталоге demo определим новый файл module-info.java со следующим кодом:

Этот файл представляет дескриптор модуля (module descriptor). Этот файл может содержать только определение модуля.

С помощью ключевого слова module определяется модуль, который называется demo, то есть так же, как и каталог, в котором данный файл расположен. После имени модуля с помощью фигурных скобок можно определить тело модуля, но в данном случае код модуля не содержит никаких инструкций.

В папке com/metanit/hello определим новый файл Hello.java :

В итоге у нас получится следующая стуктура проекта:

Что такое модуль в java. Смотреть фото Что такое модуль в java. Смотреть картинку Что такое модуль в java. Картинка про Что такое модуль в java. Фото Что такое модуль в java

Теперь скомпилируем все это. Для этого вначале перейдем в командной строке/терминале к папке, в которой находится модуль demo.

Затем для компиляции модуля выполним следующую команду:

После компиляции модуля demo выполним программу с помощью следующей команды:

И на консоли отобразится сообщение «Hello Demo Module!»

Источник

Модули Java 9 и внедрение зависимостей: используем Guice

Вот и пятница, до выходных еще далеко, поэтому мы надеемся, что сравнительно сложный текст вас не очень смутит.

Складывается впечатление, что модульная организация Java 9 потребует от программиста недюжинной изобретательности, и один из перспективных вариантов адаптации к такому дивному новому миру — это внедрение зависимостей. Именно по этому поводу внятно и интересно высказался в блоге O’Reilly уважаемый Пол Бэккер (Paul Bakker), один из авторов книги «Java 9 Modularity»

Что такое модуль в java. Смотреть фото Что такое модуль в java. Смотреть картинку Что такое модуль в java. Картинка про Что такое модуль в java. Фото Что такое модуль в java

Приятного чтения и не забудьте проголосовать пожалуйста!

В этой статье мы рассмотрим, как можно сочетать модульную систему Java 9, внедрение зависимостей и использовать сервисы, чтобы ослабить связь между модулями.

Практически невозможно представить такую базу кода на Java, где не было бы внедрения зависимостей. Поэтому, что неудивительно, внедрение зависимостей может серьезно пригодиться, чтобы ослабить связанность кода. Слабая связанность достигается путем сокрытия реализации. Ослабление связи – ключевой фактор для удобства поддержки и расширяемости кода. Фактически, в Java эта стратегия сводится к программированию на основе интерфейсов, а не конкретных типов.

В долгосрочной перспективе такое ослабление связи упрощает поддержку кода, поскольку ясно, что делает каждая часть кода, и каждый модуль можно менять, не затрагивая всю остальную систему и даже не вполне понимая, как именно она устроена. Это одна из ключевых концепций модульности. Если код организован в виде модулей, то становится проще модифицировать отдельные части системы, что очень кстати как для поддержки, так и для расширяемости. Обратите внимание: при проектировании в расчете на модульность готовая модульная система не требуется, но, если она будет, это сильно все упростит.

Всякий раз, разбивая подобную систему на модули, мы сталкиваемся с проблемой практического характера. Как добиться слабой связанности между CLI/GUI и анализаторами? Ведь в какой-то момент нам непременно потребуется создать экземпляр класса реализации. Классическое решение такой проблемы – внедрение зависимости, либо, иными словами, инверсия управления. Если мы воспользуемся внедрением зависимости, то наш код CLI/GUI просто объявит, что ему нужны экземпляры интерфейса Analyzer ; обычно это делается при помощи аннотаций. Фактическое инстанцирование классов реализации и привязка их к коду CLI/GUI выполняется при помощи фреймворка для внедрения зависимостей – популярными примерами таких фреймворков являются Spring и Guice. В этой статье используется Guice, но в книге Java 9 Modularity также есть подробный пример на основе Spring.

Что лучше при работе с модулями: внедрение зависимостей или инкапсуляция?
Java 9 и модульная система этой версии языка позволяет вывести «развязывание» кода на новый уровень. Раньше можно было программировать в расчете на интерфейсы, но по-настоящему скрыть классы реализации не удавалось. До версии Java 9 в Java, в сущности, было невозможно инкапсулировать классы в модуле (и даже объявить модуль, если на то пошло). Ситуация меняется с появлением модульной системы Java 9, однако, здесь же возникает ряд новых проблем при работе с фреймворками для внедрения зависимостей.

Если изучить внутреннее устройство фреймворков для внедрения зависимостей, то выясняется, что фреймворк требует доступа либо для глубокой рефлексии, либо для чтения к обоим классам реализации, которые нужно внедрить, а также доступа для глубокой рефлексии к тем классам, в которые предполагается внедрить этот экземпляр. При модульной организации систем такой подход работает плохо. Классы реализации должны внедряться в свой модуль, а это означает, что код, расположенный вне модуля, будет лишен доступа к этим классам (даже при применении рефлексии). Фреймворк для внедрения зависимостей – всего лишь еще один модуль, подчиняющийся все тем же правилам модульной системы, а это означает, что у фреймворка не будет доступа к этим классам. Таким образом, нам придется ослабить инкапсуляцию, а это нехорошо.

Рассмотрим типичную настройку Guice.

В этом главном методе осуществляется начальная загрузка фреймворка Guice с несколькими модулями Guice (не путайте их с модулями Java 9!). В каждом модуле есть одна или более реализаций для интерфейсов, которые мы собираемся внедрять. Например, модуль ColemanModule мог бы выглядеть так.

Что такое модуль в java. Смотреть фото Что такое модуль в java. Смотреть картинку Что такое модуль в java. Картинка про Что такое модуль в java. Фото Что такое модуль в java

Рис. 1. Зависимости между модулями: налицо сильное связывание

Свидетельствуют ли эти новые проблемы, что с модулями сложно работать? Отнюдь! Модули наконец-то позволяют нам инкапсулировать код, и это серьезный шаг к такому проектированию «со слабым связыванием», к которому мы стремимся. Существующие фреймворки не рассчитаны на эти новые возможности, поэтому, возможно, нам потребуется немного пересмотреть работу с ними. Однако, сейчас я покажу, какой великолепный обходной маневр на данный случай предлагает Guice.

Прежде чем решить эту задачу, давайте рассмотрим, что предлагает сама модульная система, чтобы обеспечить работу с инкапсулированными типами реализациями между разными модулями.

Использование сервисов в качестве альтернативы внедрению зависимостей

В модульной системе встроена специальная возможность для ослабления связи между модулями. При помощи сервисов модуль может объявить, что в нем предоставляется реализация интерфейса. Другие модули могут объявлять, что используют этот интерфейс. Система модулей передает реализации тому модулю, который использует сервис, причем, модулю не требуется читать тип реализации, даже нет необходимости предоставлять зависимость от предоставляющего модуля.

Такой новый дизайн на основе сервисов представлен на следующем рисунке. Как видите, сервисы отлично подходят для ослабления связи между модулями, и, поскольку этот подход разработан специально для системы модулей, он не требует так же жертвовать инкапсуляцией, как пришлось бы при применении фреймворка для внедрения зависимостей вроде Guice. Сервисы не идентичны внедрению зависимостей, поскольку API ServiceLoader ищет реализации, а не внедряемые зависимости, но подход с сервисами решает ту же проблему. Во многих практических ситуациях разумнее воспользоваться сервисами, а не полагаться на внешние фреймворки.

Что такое модуль в java. Смотреть фото Что такое модуль в java. Смотреть картинку Что такое модуль в java. Картинка про Что такое модуль в java. Фото Что такое модуль в java
Рис. 2. Ослабление связывания при помощи сервисов

Что, если мы все равно хотим использовать Guice, поскольку нам придется работать с уже имеющейся базой кода, основанной на Guice – либо если нам попросту нравится декларативная природа внедрения зависимостей? Можно ли лучше совместить этот фреймворк с модульной системой? Оказывается, комбинация с Guice – очень красивое решение!

Сочетание внедрения зависимостей с сервисами

Как мы уже убедились, основная проблема при работе с Guice – возникновение непосредственной связи между модулем CLI/GUI и модулями анализаторов. Все дело в том, что нам требуются классы AbstractModule для начальной загрузки Guice. Что, если бы удалось вообще исключить этот шаг и предоставлять классы AbstractModule в виде сервисов?

Пакет реализации все равно должен оставаться открыт для глубокой рефлексии, так как Guice необходима возможность инстанцировать классы. Невелика проблема, поскольку здесь мы не привносим в код никаких лишних связей, от которых стоило бы избавиться.

Итак, мы вкратце обсудили, как внедрение зависимостей помогает бороться со связанностью кода, и какие осложнения возможны при работе с имеющимися фреймворками внедрения зависимостей, например, с Guice, когда мы инкапсулируем наш код в модулях. Сервисы могут послужить встроенной альтернативой зависимостям, а комбинация сервисов и Guice удобна при внедрении зависимостей, и отказываться от инкапсуляции в таком случае также не приходится.

Весь исходный код для этой статьи выложен на GitHub. Там две ветки: одна с использованием сервисов, как показано в последнем примере, а другая – без них.

Источник

Модули в Java с примерами

Модуль Java – это механизм для упаковки вашего приложения и пакетов в модули. Может указать, какие из пакетов, которые он содержит, должны быть видны другим модулям, использующим его. Также должен указывать, какие другие модули необходимы для выполнения своей работы.

Преимущества

Java Platform Module System дает нам несколько преимуществ для разработчиков. Перечислим самые большие преимущества ниже.

Распространяемые приложения меньшего размера через модульную платформу

В рамках проекта Jigsaw все API-интерфейсы платформы были разделены на отдельные модули. Преимущество разделения состоит в том, что теперь можете указать, какие модули платформы требуется вашему приложению. Зная это, Java может упаковать приложение, включая фактически используемые.

До Java 9 и Java Platform Module System приходилось упаковывать все API-интерфейсы Java Platform с вашим приложением, потому что не было официального способа надежной проверки того, какие классы оно использовало. Поскольку API Java Platform с годами становились достаточно большими, приложение получило бы большое количество классов, включенных в его дистрибутив, многие из которых, вероятно, не использовались бы.

Неиспользуемые классы делают приложение больше, чем нужно. Это может быть проблемой на небольших устройствах, таких как мобильные телефоны, Raspberry Pis и т. д. С модульной системой вы можете теперь упаковать свое приложение только с теми модулями API, которые ваше приложение фактически использует. Это приведет к меньшим объемам приложения.

Инкапсуляция внутренних пакетов

Модуль должен явно указывать, какие пакеты внутри него должны быть экспортированы (видимы) в другие модули с помощью него. Может содержать пакеты, которые не экспортируются. Классы в неэкспортированных пакетах не могут использоваться другими модулями, только внутри содержащего их.

Обнаружение запуска отсутствующих модулей

Начиная с Java 9 и выше, приложение также должно быть упаковано как модуль. Он определяет, какие другие модули (API Java или сторонних производителей) использует. Поэтому Java VM может проверять весь граф зависимостей модульной системы от модулей приложения при запуске VM. Если какие-либо обязательные не найдены, виртуальная машина сообщает об этом и завершает работу.

До Java 9 отсутствующие классы (например, из отсутствующего файла JAR) не обнаруживались до тех пор, пока приложение фактически не попыталось использовать его.

Наличие отсутствующих модулей, о которых сообщается во время запуска приложения, является большим преимуществом по сравнению со временем выполнения при попытке использовать его.

Основы

Теперь, когда вы знаете, что такое модуль и каковы преимущества его, давайте взглянем на основы.

Содержат один или несколько пакетов

Модуль – это один или несколько пакетов Java, которые принадлежат друг другу. Может быть либо полным приложением, API-платформой, либо сторонним API.

Наименование

Должен иметь уникальное имя. Например, допустимое имя может быть:

Имя следует тем же правилам именования, что и для пакетов. Однако не следует использовать подчеркивания (_). В Java 9 и более поздних версиях допустимо использовать подчеркивание в качестве зарезервированного идентификатора.

Рекомендуется называть модуль так же, как и имя корневого пакета, содержащегося в нем. Если это возможно (в некоторых случаях может содержаться несколько корневых пакетов).

Корневой каталог

До Java 9 все классы для приложения или API были вложены непосредственно в каталог корневого класса (который был добавлен в путь к классам) или непосредственно в файл JAR. Например, структура каталогов для скомпилированных пакетов com.blog.mymodule будет выглядеть следующим образом:

Чуть графически это будет выглядеть так:

Начиная с Java 9, модуль должен быть вложен в корневой каталог с тем же именем, что и он сам. В приведенном выше примере у нас есть структура каталогов для пакета с именем com.blog.mymodule. Он должен содержаться в модуле с тем же именем (также com.blog.mymodule).

Структура в этом случае будет выглядеть следующим образом:

Чуть графически это будет выглядеть так:

Обратите внимание на полную остановку (.) в имени корневого каталога модуля. Они обязательны, потому что являются частью имени! Не должны интерпретироваться как разделители пути подкаталогов!

Корневой каталог используется как для исходных файлов, так и для скомпилированных классов. Это означает, что если ваш проект имеет корневой каталог источника с именем src / main / java – тогда каждый модуль в проекте будет иметь свой собственный корневой каталог в каталоге src/main/java. Например:

Такая же структура каталогов будет видна в выходном каталоге компилятора.

Обычно в одном проекте используется только один модуль. В этом случае вам все равно понадобится корневой каталог, но выходные корневые каталоги исходного кода и компилятора будут содержать только один корневой каталог.

Дескриптор (module-info.java)

Каждый модуль нуждается в дескрипторе с именем module-info.java, который должен находиться в соответствующем корневом каталоге. Для корневого каталога src / main / java / com.blog.mymodule путь к дескриптору будет src / main / java / com.blog.mymodule / module-info.java.

Дескриптор указывает, какие пакеты экспортирует модуль, и какие еще требуются ему. Вот как выглядит базовый пустой дескриптор:

Сначала следует ключевое слово module, за которым имя модуля, а затем набор фигурных скобок. Экспортированные пакеты и необходимые модули будут указаны в них.

Экспорт

Модуль обязан явно экспортировать все пакеты в нем, которые должны быть доступны для других модулей, использующих его. Экспортируемые пакеты объявляются в дескрипторе. Простое объявление:

В этом примере экспортируется пакет с именем com.blog.mymodule.

Обратите внимание, что экспортируется только сам перечисленный пакет. Никакие «подпакеты» экспортируемого пакета не экспортируются. Это означает, что если пакет mymodule содержал подпакет с именем util, то пакет com.blog.mymodule.util * не * экспортируется только потому, что com.blog.mymodule.

Чтобы экспортировать подпакет также, вы должны объявить его явно в дескрипторе, например так:

Вам не нужно экспортировать родительский пакет, чтобы экспортировать подпакет. Следующий оператор экспорта дескриптора совершенно корректен:

В этом примере экспортируется только пакет com.blog.mymodule.util, а не пакет com.blog.mymodule.

Требуется другой модуль

Если для работы модуля требуется другой, он также должен быть указан в дескрипторе:

В этом примере дескриптор объявляет, что ему требуется стандартный модуль с именем javafx.graphics.

Круговые зависимости не допускаются

Не допускается наличие циклических зависимостей между модулями. Другими словами, если один из них (A) требует другой (B), то B не может также требовать A. Граф зависимостей модуля должен быть ациклическим графом.

Разделение пакетов не разрешено

Один и тот же пакет может быть экспортирован только одним модулем во время выполнения.

Наличие двух модулей, экспортирующих один и тот же пакет, также иногда называется разделенным пакетом. Под “разделить пакет” подразумевается, что общий контент (классы) пакета разделен между несколькими модулями. Это не разрешено.

Компиляция

Чтобы скомпилировать модуль, вам необходимо использовать команду javac, которая поставляется с Java SDK.

Помните, вам нужна Java 9 или новее.

Помните, что для работы этой команды у вас должна быть команда javac из установки JDK на вашем пути (переменная среды).

В качестве альтернативы вы можете заменить часть javac в приведенной выше команде на полный путь к расположению команды javac, например так:

–Module-source-path должен указывать на корневой каталог источника, а не на корневой каталог модуля. Корневой каталог источника обычно находится на один уровень выше модульного корневого каталога.

Аргумент –module указывает, какой модуль компилировать. Вы можете указать их несколько, разделяя имена запятой. В приведенном выше примере это com.blog.mymodule. Например:

Запуск

Для запуска основного класса вы используете команду java, например:

Аргумент –module-path указывает на корневой каталог, в котором находятся все скомпилированные модули. Помните, это на один уровень выше модульного корневого каталога.

Аргумент –module указывает, какой модуль + основной класс запустить. В этом примере имя модуля является частью com.blog.mymodule, а имя основного класса – com.blog.mymodule.Main.

Обратите внимание, что имя модуля и имя основного класса разделены косой чертой (/).

Создание файла JAR

Вы можете упаковать модуль внутри стандартного файла JAR. Вы делаете это с помощью стандартной команды jar, которая поставляется с Java SDK. Иерархия каталогов пакетов должна начинаться с корня файла JAR, как и для файлов JAR до Java 9. Кроме того, файл JAR модуля содержит скомпилированную версию дескриптора в корне файла JAR.

Аргумент –file указывает путь к выходному файлу – созданному файлу JAR. Любые каталоги, в которые вы хотите поместить выходной JAR-файл, должны уже существовать!

Установка JAR основного класса

Вы все еще можете установить основной класс JAR при генерации файла JAR модуля. Вы делаете это, предоставляя аргумент –main-class:

Теперь вы можете запустить основной класс этого JAR-файла с помощью ярлыка. Этот ярлык будет объяснен в следующем разделе.

Запуск из JAR

После того, как вы упаковали свой модуль в файл JAR, вы можете запустить его так же, как и обычный. Просто включите файл JAR модуля в путь. Вот как вы запускаете основной класс из файла JAR:

Для работы этой команды файл JAR модуля должен находиться в каталоге out-jar.

Запуск из JAR с набором основного класса

Если в файле JAR модуля установлен основной класс, вы можете запустить его с помощью более короткой командной строки:

Обратите внимание, как не установлен аргумент –module-path. Это требуется, чтобы модуль не использовал сторонние модули. В противном случае вы также должны указать аргумент –module-path, чтобы Java VM могла найти их.

Упаковка как отдельного приложения

Вы можете упаковать модуль вместе со всеми необходимыми модулями (рекурсивно) и среду выполнения Java в автономное приложение. Пользователю такого приложения не требуется предварительно устанавливать Java для запуска приложения.

Вы упаковываете модуль в автономное приложение, используя команду jlink, которая поставляется вместе с Java SDK:

Аргумент –module-path указывает пути к модулям, в которых нужно искать их. В приведенном выше примере указывается каталог out, в который мы предварительно скомпилировали наш модуль, и каталог jmods установки JDK.

Аргумент –add-modules указывает модули для упаковки в автономное приложение. В приведенном выше примере просто включен com.blog.mymodule.

Аргумент –output указывает, в какой каталог записать сгенерированное автономное приложение. Каталог не должен уже существовать.

Запуск автономного приложения

После упаковки вы можете запустить автономное приложение, открыв консоль (или терминал), перейдя в каталог автономного приложения и выполнив следующую команду:

Автономное приложение содержит каталог bin с исполняемым файлом. Он используется для запуска приложения.

Аргумент –module указывает, какой модуль плюс основной класс запускать.

Безымянный

Начиная с Java 9 и далее все классы должны быть расположены в модуле, чтобы виртуальная машина могла их использовать. Но что вы делаете со старыми библиотеками, где у вас есть только скомпилированные классы или файл JAR?

Безымянный экспортирует все свои пакеты. Однако классы доступны для чтения только другим классам в нем. Ни один из названных модулей не может читать классы безымянного.

Если пакет экспортируется указанным модулем, но также обнаруживается в неназванном, будет использоваться пакет из названного.

Для всех классов в неназванном требуются все модули, найденные в его пути. Таким образом, все классы в безымянном могут читать все классы, экспортируемые всеми модулями, найденными в его пути.

Автоматические

Что если вы модулируете свой собственный код, но он использует стороннюю библиотеку, которая еще не является модульной? Хотя вы можете включить стороннюю библиотеку в путь к классам и, таким образом, включить ее в безымянный модуль, ваши собственные именованные не могут ее использовать, поскольку именованные не могут читать классы из безымянного.

Решение – автоматический модуль. Сделан из файла JAR с классами, которые не являются модульными, то есть файл JAR не имеет дескриптора. Это касается файлов JAR, разработанных с использованием Java 8 или более ранних версий. Когда вы помещаете обычный JAR-файл в путь модуля (а не в путь к классам), Java VM преобразует его в автоматический модуль во время выполнения.

Требуются все именованные модули в пути основного. Другими словами, он может читать все пакеты, экспортируемые всеми именованными модулями в пути модуля.

Если ваше приложение содержит несколько автоматических модулей, каждый может читать классы всех других таких же.

Может читать классы в неназванном модуле. Это отличает от явно названных (реальных), которые не могут читать классы в безымянном.

Экспортирует все свои пакеты, поэтому все именованные виды в пути модуля могут использовать классы автоматического. Именованные все еще должны явно требовать автоматический вид.

Правило о запрете разделения пакетов также учитывается для автоматических видов. Если несколько файлов JAR содержат (и, следовательно, экспортируют) один и тот же пакет, то только один из этих файлов JAR можно использовать в качестве автоматического модуля.

Если файл JAR содержит версии в имени файла, например com-blog-mymodule-2.9.1.jar, то часть контроля версий также удаляется из имени файла, прежде чем будет получено автоматическое имя модуля. Получающееся имя – com.blog.mymodule.

Сервисы

С Java 9 приходит новая концепция, называемая сервисами. Службы связаны с модульной системой платформы. Сервис состоит из двух основных частей:

Интерфейс службы обычно располагается в модуле интерфейса службы, который содержит только интерфейс службы плюс любые классы и интерфейсы, связанные с интерфейсом службы.

Реализации сервиса предоставляются отдельными модулями, а не модулям интерфейса сервиса. Обычно модуль реализации службы будет содержать одну реализацию службы.

Для модуля или приложения может потребоваться модуль и код интерфейса службы, не зная точно, какой другой модуль обеспечивает реализацию службы. Реализация сервиса обнаруживается во время выполнения и зависит от того, какие модули реализации сервиса доступны на пути к модулю при запуске приложения.

Сервисный интерфейс

Модули интерфейса службы не требуют специального объявления интерфейса службы. Вы просто создаете обычный модуль:

Обратите внимание, что фактический интерфейс службы не упоминается. Модуль интерфейса службы экспортирует только пакет, который содержит интерфейс службы – обычный интерфейс.

Реализация сервиса

Модуль, который хочет реализовать интерфейс службы из модуля интерфейса службы, должен:

Представьте, что модуль com.blog.myservice содержит интерфейс с именем com.blog.myservice.MyService. Представьте также, что вы хотите создать модуль реализации сервиса для этого интерфейса сервиса. Реализация называется com.blabla.myservice.MyServiceImpl. Чтобы объявить ее, дескриптор должен выглядеть следующим образом:

Дескриптор сначала объявляет, что ему требуется модуль интерфейса службы. Потом объявляет, что он обеспечивает реализацию для интерфейса службы com.blog.myservice.MyService через класс com.blabla.myservice.MyServiceImpl. Теперь нам нужно посмотреть, как модуль может искать реализацию интерфейса службы во время выполнения.

Сервисный клиентский

Чтобы использовать сервис, клиентский вид должен объявить в своем дескрипторе, что он использует сервис:

Обратите внимание, что дескриптор клиентского модуля также объявляет, что ему требуется модуль com.blog.myservice, который содержит интерфейс службы. Для этого не нужны сервисные модули реализации, которые ищутся во время выполнения. Требуется только модуль интерфейса сервиса.

Преимущество отсутствия необходимости объявлять модули реализации службы состоит в том, что они могут заменяться без нарушения клиентского кода. Вы можете решить, какую реализацию сервиса использовать при сборке приложения – перетащив нужные модули реализации сервиса на путь к модулю. Клиентский вид и интерфейс службы, таким образом, отделены от модулей реализации службы.

Теперь клиентский модуль службы может искать реализацию интерфейса службы во время выполнения следующим образом:

Возвращаемый Iterator содержит список реализаций интерфейса MyService. Фактически, он будет содержать все реализации, найденные в модулях, найденных в пути. Клиентский теперь может выполнять итерацию итератора и находить реализацию сервиса, которую он хочет использовать.

Управление версиями

Модульная система платформы не поддерживает управление версиями модулей. Вы не можете иметь несколько версий модуля по пути к нему при запуске приложения Java 9+. Вам потребуется использовать инструмент сборки, такой как Maven или Gradle, для управления версиями, а также внешние модули, от которых зависит ваш (использует / требует).

JAR-файлы Multi Java Version

Из Java 9 можно создавать файлы JAR для модулей, которые содержат код, скомпилированный специально для различных версий Java. Это означает, что вы можете создать файл JAR для вашего модуля, который содержит код, скомпилированный для Java 8, Java 9, Java 10 и т. д. – все в одном и том же файле JAR.

Вот как выглядит структура JAR-файла с несколькими версиями:

Папка com на корневом уровне файла JAR содержит скомпилированные классы для версий до Java 9. Более ранние версии не понимают файлы JAR с несколькими версиями, поэтому они используют классы, найденные здесь. Поэтому вы можете поддерживать только одну версию раньше, чем Java 9.

Каталог META-INF содержит файл MANIFEST.MF и каталог с именем version. Файл MANIFEST.MF нуждается в специальной записи, которая помечает JAR-файл как мульти-версия JAR-файла. Вот как выглядит эта запись:

Каталог версий, который может содержать скомпилированные классы для разных версий для вашего модуля. В приведенном выше примере в каталоге версий есть два подкаталога. Один подкаталог для Java 9 и один для Java 10. Названия каталогов соответствуют номерам поддерживаемых версий.

Миграция на Java 9

Части модульной системы Java Platform предназначены для облегчения миграции приложений, написанных на предыдущих версиях Java 9, на Java 9. Она разработана для поддержки миграции «снизу вверх» – это означает, что вы сначала мигрируете свои небольшие служебные библиотеки и свои основные приложения.

Миграция предназначена для:

Обновление снизу вверх повышает вероятность того, что ваши приложения смогут работать в тот период, пока все не будет обновлено до модулей. Предполагается, что ваше приложение сможет работать на любом из указанных этапов.

Обновление служебных библиотек сначала до автоматических, а затем до полных модулей, начиная с нижней части иерархии зависимостей, должно гарантировать, что ваши библиотеки все еще могут читать друг друга во время обновления, а также быть доступными для чтения основными приложениями на пути к классам в неназванном модуле.

Примечание. Если есть вероятность, что вы обновите все за одно большое обновление, это, скорее всего, будет самый простой путь обновления. Конечно, у вас будет время, когда вы не сможете собрать работающее приложение, но как только вы обновитесь, приложение заработает!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *