Почему в Java 9 появился формат файла JMOD?
В Java 9 есть три способа упаковки скомпилированного кода в файлы:
- JAR
- JMOD
- j Качество изображения
JIMAGE оптимизирован для скорости и пространства и используется JVM во время выполнения, поэтому имеет смысл, почему был представлен JIMAGE. Файлы JIMAGE не должны публиковаться в репозиториях Maven или использоваться во время компиляции или компоновки.
Документы утверждают, что JMOD может хранить собственный код и другие вещи, которые не могут быть сохранены файлами JAR, и что разработчики могут создавать и распространять свои собственные файлы JMOD. JDK поставляется с jmods/
каталог, содержащий все модули JDK, от которых зависят пользователи.
Вопросы:
- Почему в Java 9 появился формат файла JMOD?
- Должен ли автор библиотеки распространять файл JMOD или файл JAR, или оба?
- Должны ли файлы jmod быть опубликованы в репозиториях Maven?
1 ответ
Назначение JMOD плохо документировано, а существующая документация довольно скудна. Вот подробное объяснение системы, насколько я понимаю.
Предупреждение: части этого ответа довольно длинные, подробные, частично повторяющиеся и трудные для чтения. Конструктивные, структурные или грамматические правки более чем приветствуются, чтобы улучшить читаемость для будущих читателей.
Короткий (эр) ответ
Новая модульная система Java 9, Project Jigsaw, вводит понятие новой необязательной фазы времени компоновки, которая возникает при использовании инструмента CLI jlink
для создания собственной оптимизированной по пространству JRE.
jlink
объединяет все явные / транзитивные модули JAR / зависимости JMOD в минифицированную JRE; все другие недостижимые зависимости в графе зависимостей (начиная с указанных корневых модулей) не входят в состав встроенной JRE. Начиная с JDK 9+, вся стандартная библиотека Java была разбита на JMOD, расположенные по адресу
<jdk>/jmods
.
В то время как JAR могут содержать только
.class
и файлы ресурсов, JMOD (т.е.
.jmod
files) содержат дополнительные файлы, которые используются специально в новой необязательной фазе времени компоновки для настройки JRE (например, исполняемые файлы, собственные библиотеки, конфигурации, юридические лицензии и т. д.). Эти дополнительные файлы недоступны в качестве ресурсов во время выполнения в пути к классам, но вместо этого устанавливаются в различных местах встроенной JRE (например, исполняемые файлы и собственные библиотеки помещаются в
<jre>/bin
). Из соответствующих связанных зависимостей JAR и JMOD классы и файловые ресурсы будут записаны в один оптимизированный файл JIMAGE, расположенный по адресу
<jre>/lib/modules
(заменяя
<jre>/lib/rt.jar
в Java 8 и предыдущих версиях). Роль JMOD - во время компиляции и компоновки, и они не предназначены для использования во время выполнения.
Для средней библиотеки / приложения следует создавать и размещать только JAR, а не JMOD; только при определенных условиях модули JMOD будут предлагать критически важные функции, необходимые на этапе компоновки. На момент написания Maven, похоже, не предлагает сильной поддержки JMOD, кроме плагина альфа-версии. org.apache.maven.plugins:maven-jmod-plugin
.
Длинный ответ
Этот многословный ответ имеет более сложную мотивацию и проливает свет на фундаментальные принципы работы новой модульной системы. В этом посте сильный акцент делается на инструменте CLI.
jlink
, поскольку JMOD разработаны специально для этой новой необязательной фазы времени компоновки, которую вводит инструмент.
Введение в Project Jigsaw
Java 9 представила Project Jigsaw в " JEP 261: Module System ", новой модульной системе, которая может использоваться для минимизации времени запуска и размера JRE. В рамках этого выпуска утилиты CLI jmod
,
jimage
, и jlink
были введены вместе с новыми форматами файлов для JMOD /
.jmod
s (на основе ZIP) и JIMAGE /
.jimage
с.
Важный вывод этой новой модульной системы заключается в том, что инструмент CLI
jlink
позволяет разработчикам создавать собственную JRE, содержащую только соответствующую стандартную библиотеку и внешние зависимости для их приложений. Это вводит новое понятие необязательной фазы времени связи между традиционными фазами в
compile time -> run time
трубопровод.
Для примера преимуществ использования
jlink
, минималистичный JRE, созданный на основе JDK 15 только с
java.base
модуль имеет размер примерно ~40 МБ, что резко контрастирует с размером JDK 15 ~310 МБ. Это особенно полезно для доставки минимальной настраиваемой JRE, например для упрощенных образов Docker. Новая модульная система приносит значительные преимущества экосистеме Java, которые подробно обсуждались в другом месте и поэтому здесь не рассматриваются.
3 J: JAR, JMOD и JIMAGE
Описание высокого уровня JAR, JMOD и JIMAGE не поддается объяснению, которое сильно различает роли трех форматов файлов. Вот неполный обзор целей каждого из них:
JAR: классический формат, основанный на формате файла ZIP для объединения классов и ресурсов в путь к классам во время выполнения. Это де-факто основной стандарт, установленный с JDK 1.1 в 1997 году. JAR-файлы могут быть добавлены в путь к классам с помощью
java
-cp
/-classpath
флаги. Практически каждая библиотека или зависимость имеет, есть и будет использовать этот формат, поэтому в этом разделе он замалчивается.JMOD: новый формат, основанный на формате файла ZIP для объединения того же содержимого, которое может содержать JAR, но с поддержкой дополнительных файлов (например, исполняемых файлов, собственных библиотек, конфигураций, юридических лицензий и т. Д.), Которые используются во время необязательной компоновки. этап при создании пользовательской JRE.JMOD предназначены для использования как во время компиляции, так и во время компоновки, но не во время выполнения. Этот новый формат, вероятно, был введен (вместо расширения JAR), потому что для каталогов в этом новом формате на основе архивов есть особое значение, которое не имеет обратной совместимости с JAR, которые уже используют те же имена каталогов.
- JMOD может быть построен из модуля JAR (т.е. содержит действительный
module-info.class
) с помощью инструмента CLIjmod
. - Начиная с JDK 9 и новее, все стандартные модули Java хранятся в
<jdk>/jmods
в установке JDK. - JMOD могут быть опубликованы для использования другими разработчиками и приложениями верхнего уровня; на момент написания я не уверен, могут ли JMOD быть отправлены в репозитории Maven, но различные источники, похоже, указывают на то, что это не так.
- Классы и ресурсы JMOD не могут быть использованы в период выполнения в пути к классам с
java
-cp
/-classpath
flags, поскольку классы и ресурсы внутри архива JMOD хранятся вclasses
а не в корне архива.
- JMOD может быть построен из модуля JAR (т.е. содержит действительный
Примечание. Может быть способ легко добавить JMOD в путь к классам во время выполнения; тем не менее, в исследовании явно не указывались какие-либо функции, относящиеся к этому. Простого добавления JMOD в путь к классам будет недостаточно для использования классов и ресурсов. Обычай
ClassLoader
однако может использоваться для правильного разрешения файлов классов и ресурсов в архиве JMOD во время выполнения; обычно это не рекомендуется и не является целью JMOD.
- JIMAGE: специальный формат файла, представленный в " JEP 220: модульные изображения времени выполнения ", который представляет собой образ времени выполнения, содержащий все необходимые классы и ресурсы для JRE (то есть стандартной библиотеки). До JRE/JDK 9 использовался один большой немодульный uber JAR, расположенный в
<jre>/lib/rt.jar
; с тех пор он был удален в пользу единственного оптимизированного хранилища JIMAGE, расположенного в<jre>/lib/modules
. Этот формат не основан на формате ZIP и использует специальный формат, который значительно эффективнее по времени и пространству, чем исходный устаревший формат JAR, что сокращает время запуска.- При создании пользовательского образа JRE с помощью инструмента CLI
jlink
все соответствующие (явные или транзистивные) классы и ресурсы зависимостей модулей (из модулей JAR или JMOD) компилируются в один оптимизированный файл JIMAGE (опять же, хранящийся в<jre>/lib/modules
). - Формат файла JIMAGE является модульным, и его можно создавать, изменять, разбирать или проверять с помощью инструмента CLI.
jimage
. Напримерjimage list $JAVA_HOME/lib/modules
- Файлы JIMAGE, как правило, не следует публиковать, а следует поставлять с определенной пользовательской версией JRE; формат файла может быть изменен в будущем.
- При создании пользовательского образа JRE с помощью инструмента CLI
Сущность: подробное назначение JMOD
Новая дополнительная фаза времени соединения
Как было сказано несколько раз ранее, инструмент командной строки jlink
вводит новый необязательный этап в обычном конвейере Java - этап времени компоновки. Эта фаза времени компоновки используется для создания специально созданной JRE из набора модулей Java 9 (либо JAR с
module-info.java
дескриптор или JMOD).
Вкратце этапы высокого уровня описываются следующим образом:
время компиляции (
javac
): Как описано наjavac
документация, этап компиляции...... читает определения классов и интерфейсов, написанные на языке программирования Java, и компилирует их в файлы классов байт-кода. Он также может обрабатывать аннотации в исходных файлах и классах Java.
время ссылки (
jlink
): Как описано в 'JEP 282: jlink: The Java Linker', фаза времени компоновки...... необязательный этап между этапами времени компиляции (команда javac) и времени выполнения (средство запуска java). Время связывания требует инструмента связывания, который будет собирать и оптимизировать набор модулей и их транзитивных зависимостей для создания образа времени выполнения или исполняемого файла.
Время компоновки - это возможность выполнить глобальную оптимизацию, которая в противном случае была бы сложной во время компиляции или дорогостоящей во время выполнения. Примером может служить оптимизация вычислений, когда все его входные данные становятся постоянными (т. Е. Не неизвестными). Последующей оптимизацией будет удаление кода, который больше не доступен.время выполнения (
java
): Как описано наjavac
документация, этап выполнения...... запускает приложение Java. Для этого он запускает среду выполнения Java (JRE), загружает указанный класс и вызывает метод main() этого класса.
Введение JMOD
Во время фазы компоновки все классы и ресурсы из модулей (действительные модули JAR или формы JMOD)
classes
) компилируются в один оптимизированный образ времени выполнения JIMAGE, расположенный по адресу
<jre>/lib/modules
. Модули, не включенные явно или транзитивно, не будут включены в этот окончательный JIMAGE, что сэкономит значительное количество места. Однако при создании собственной JRE могут потребоваться некоторые дополнительные файлы внутри JRE; например, исполняемые команды или собственные библиотеки. Для модулей JAR история на этом заканчивается - это не способ для JAR добавлять файлы (помимо классов, включенных в JIMAGE) во встроенную JRE без неоднозначности.
Введение в JMOD: JMOD могут добавлять дополнительные файлы в специально созданную JRE; несколько примеров (но не обязательно исчерпывающих): исполняемые команды, файлы конфигурации, файлы заголовков, юридические уведомления и лицензии, собственные библиотеки и страницы руководства. Это позволяет зависимости модуля формировать построенную JRE по-своему. Поведение того, как эти дополнительные файлы вставляются во встроенную JRE с помощью инструмента CLI
jlink
документируются в следующем разделе.
JMOD предназначены исключительно для фаз компиляции и времени компоновки, как описано в 'JEP 261: Модульная система ':
Файлы JMOD можно использовать во время компиляции и компоновки, но не во время выполнения. Для их поддержки во время выполнения, как правило, мы должны быть готовы извлекать и связывать библиотеки машинного кода на лету. Это возможно на большинстве платформ, хотя это может быть очень сложно, и мы не видели много вариантов использования, которые требовали бы этой возможности, поэтому для простоты мы решили ограничить полезность файлов JMOD в этом выпуске.
Новый формат - отсутствие обратной совместимости с JAR
Хороший вопрос может быть: "Почему бы не разрешить JAR-файлам добавлять поведение во время компоновки?". Есть подозрение, что это не обеспечивает достаточной поддержки обратной совместимости с существующими JAR-файлами и инструментами. В формате файла архива JAR нет спецификации для зарезервированных имен файлов. Если существующая библиотека хранит какие-либо ресурсы в каталогах, предназначенных для времени компоновки,
jlink
не мог точно предположить, предназначен ли он для использования во время связывания или необходим во время выполнения. Новая спецификация формата файла с зарезервированными именами каталогов решит эту проблему несовпадения - например, новый формат JMOD. С JMOD нет двусмысленности в том, какие ресурсы предназначены для времени компоновки и времени выполнения. Кроме того, формат JMOD может быть расширен для добавления новых функций в более поздних версиях JDK без проблем с обратной совместимостью.
Формат файла JMOD похож на JAR в том, что он основан на формате файла ZIP. Файл JMOD имеет следующие зарезервированные имена каталогов со следующим поведением (это не обязательно исчерпывающий список!):
-
bin
(--cmds
): Исполняемые команды, которые копируются в<jre>/bin
-
classes
(--class-path
): Предназначен для включения в окончательно собранный JIMAGE, хранящийся в / lib / modules -
conf
(--config
): Дополнительные конфигурации скопированы в<jre>/conf
; вероятно, используется для управления конфигурацией любых связанных модулей, если требуется -
include
(--header-files
): Дополнительные файлы заголовков C, которые копируются в<jre>/include/
для создания библиотек C для JVM с использованием JNI; например, вjava.base
, интерфейсы JNI экспортируются -
legal
(--legal-notices
): Юридические уведомления и лицензии для модуля, которые копируются в<jre>/legal/<module name>/
-
lib
(--libs
): Собственные библиотеки, которые копируются в<jre>/bin
Для любопытно настроенных стандартных библиотек JMOD (расположенных в
$JAVA_HOME/jmods
в JDK 9+) можно проверить с помощью любого приложения, которое читает архивы ZIP.
Основная поддержка...?
Значительная часть причины того, что JMOD не были быстро приняты и имеют плохую доступность документации, заключается в том, что, проще говоря, они не нужны для подавляющего большинства библиотек и зависимостей модулей. Хотя они по-прежнему полезны для конкретных случаев использования, модули должны использовать формат JAR, который уже получил широкую поддержку, поскольку он был определен с JDK 1.1 в 1997 году (с
module-info.java
поддержка модуля добавлена в JDK 9 в 2017 г.).
Из документации инструмента CLI jmod
:
Для большинства задач разработки, включая развертывание модулей по пути к модулю или их публикацию в репозитории Maven, продолжайте упаковывать модули в модульные файлы JAR. Инструмент jmod предназначен для модулей, которые имеют собственные библиотеки или другие файлы конфигурации, или для модулей, которые вы собираетесь связать с помощью инструмента jlink с образом времени выполнения.
Мнение: JMOD, скорее всего, не получат сколько-нибудь значительного принятия разработчиками, по крайней мере, очень долгое время. Большинство разработчиков никогда не услышат и не узнают цель JMOD - да и не должны. Модули JMOD служат важной цели для создания JRE (все модули стандартной библиотеки Java являются JMOD), но не влияют на подавляющее большинство приложений и проектов из-за их нишевого варианта использования во время компоновки. Java 9 была выпущена в 2017 году, и зависимости в экосистеме Java все еще пытаются надежно иметь
module-info.class
дескриптор, чтобы сделать JAR действительным полноценным модулем...
Выводы
- JMOD - это фундаментальная новая функция для создания JRE с помощью инструмента CLI.
jlink
что позволяет настраивать специально созданную JRE с дополнительными файлами. - Развертывайте JAR вместо JMOD, если только некоторые функции из JMOD не требуются. Модули JAR также совместимы с
jlink
, поэтому нет необходимости поставлять JMOD, который включает только классы и ресурсы. Поддержка экосистемы и инструменты не обязательно предполагают переход на JMOD в ближайшее время и наверняка будут иметь проблемы совместимости на долгие годы. - Документация Java для этой области экосистемы действительно может быть улучшена.
Отказ от ответственности
На момент написания этого ответа документации о назначении JMOD для Java 9 и последующих версий было немного. Фактически, поисковые фразы Google "java jmods" и "jmod format" вызывают тот же самый вопрос Stackru в качестве второго результата поиска. Следовательно, некоторые аспекты могут быть неточно объяснены, но, как правило, являются "ориентировочно правильными"; более того, это может не дать полной картины. Если вы обнаружите какие-либо проблемы или предостережения, оставьте комментарий, и я постараюсь согласовать его с этим ответом.
Вот некоторые цитаты из JEP 261: модульная система, которая содержит раздел о файлах JMOD.
Зачем?
От JEP 261:
Новый формат JMOD выходит за рамки файлов JAR и включает в себя собственный код, файлы конфигурации и другие виды данных, которые не вписываются в файлы JAR естественным образом или вообще не помещаются.
а также
Окончательный формат файлов JMOD является открытой, но пока он основан на ZIP-файлах.
Должен ли разработчик публиковать файлы JMOD?
Обратите внимание, что файлы JMOD, по-видимому, являются способом включения собственного кода (среди прочего) во время компиляции и во время компоновки. От JEP 261:
Файлы JMOD могут использоваться во время компиляции и во время компоновки, но не во время выполнения.
(Если честно, я не уверен, как нативный код публикуется до JDK 9.) Для подавляющего большинства разработчиков (без нативных библиотек или других примеров) мы просто опубликуем модульные фляги.