Это пятое издание серии. Для четвертого издания нажмите здесь.

Услуги

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

Как говорится, любую проблему в информатике можно решить, добавив еще один уровень косвенности, за исключением, конечно, проблемы наличия слишком большого количества слоев косвенности. Таким образом, модульная система использует тот же подход и вводит еще один уровень косвенности, который называется каталог/реестр служб. Идея состоит в том, что некоторые модули, назовем их сервис-провайдерами, могут регистрировать свой класс реализации как сервис в реестре сервисов. Этот класс реализации реализует интерфейс, как в приведенном выше случае, MyServiceImpl реализует MyService, и этот интерфейс является точкой связи между поставщиками услуг и потребителями услуг.

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

Итак, как это выглядит в коде? Давайте посмотрим на пример. Мы собираемся начать с определения модуля myApi, который экспортирует пакет com.api, содержащий интерфейс MyService.

Теперь давайте сначала посмотрим на потребительский модуль, который будет использовать сервис. Этот модуль под названием myConsumer требует myApi, что логично, потому что он должен знать об интерфейсе, чтобы вызывать его методы. Второе состояние внутри дескриптора модуля более интересно. Это указывает модульной системе, что myConsumer заинтересован в использовании экземпляров интерфейса com.api.MyService, независимо от того, откуда они поступают.

Нам также нужен модуль провайдера, который предоставляет услуги. Опять же, первое состояние в дескрипторе модуля требует myApi, и в случае с модулем провайдера это также имеет смысл, потому что провайдер должен знать об интерфейсе, чтобы реализовать его, и здесь второе утверждение в дескрипторе модуля, которое относится к обслуживание также. Итак, мы говорим модульной системе, что мы предоставляем класс, поэтому здесь он называется myProvider.MyServiceImpl и реализует интерфейс com.api.MyService. Теперь важно то, что класс реализации находится в пакете myProvider, который не экспортируется. Итак, он полностью инкапсулирован. Он не может использоваться никаким другим модулем. Однако сервисный механизм модульной системы сможет создать для нас экземпляр MyserviceImpl и предоставить его любому потребителю, который захочет использовать что-то, что реализует MyService.

Теперь возникает один вопрос, как мне получить эти экземпляры в модуле myConsumer?

Это можно сделать с помощью API загрузчика служб. Для метода загрузки требуется класс интерфейса, и он возвращает итерируемый объект, содержащий экземпляры MyService из реестра службы. Теперь мы вызываем методы, используя экземпляры. Здесь у нас есть модуль myConsumer и myProvider, которые взаимодействуют друг с другом, но не имеют жесткой связи друг с другом во время компиляции.

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

Модуль связи

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

Традиционно у нас было два отдельных этапа разработки Java. Первая фаза — это время компиляции, когда компиляция происходит из исходного кода Java в байтовый код. Скомпилированный байт-код затем переходит ко второй фазе, времени выполнения вашего кода. Связывание находится между этими фазами. Это новый необязательный шаг в разработке Java, когда вы берете результаты компиляции, точнее модули, и связываете их вместе в более эффективном формате для времени выполнения. Я хочу подчеркнуть тот факт, что связывание в java 9 является совершенно необязательным и может выполняться только при наличии модулей. Таким образом, он не предназначен для типичных приложений на основе Classpath.

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

Джлинк

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

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

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

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

jlink также проверяет зависимости модулей платформы. В этом случае оба модуля требуют java.base. Таким образом, это будет помещено в образ среды выполнения.

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

Мы можем сравнить этот образ среды выполнения с ситуацией, когда компоновщик не используется. В этом случае у вас есть полный JDK, содержащий все 90+ модулей, которые находятся на платформе Java, и модуль приложения будет помещен в путь модуля и запущен поверх этого полного JDK.

Теперь мы знаем всю информацию о модульности, но в целом не начинаем переписывать приложение. Должен быть какой-то способ перенести наше приложение на java 9. В следующем выпуске мы узнаем, что нужно сделать, чтобы подготовиться к java 9.

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

источник:
https://www.geekboots.com
https://www.pluralsight.com