Поиск…


Вступление

Одной из функций, представленной в Java 9, является многорежимный Jar (MRJAR), который позволяет связывать код с таргетингом на несколько выпусков Java в одном файле Jar. Функция указана в JEP 238 .

Пример содержимого файла Jar для нескольких выпусков

Установив Multi-Release: true в файле MANIFEST.MF, Jar-файл становится многорежимным Jar и временем выполнения Java (при условии, что он поддерживает формат MRJAR) выбирает соответствующие версии классов в зависимости от текущей основной версии ,

Структура такой банки состоит в следующем:

jar root
  - A.class
  - B.class
  - C.class
  - D.class
  - META-INF
     - versions
        - 9
           - A.class
           - B.class
        - 10
           - A.class
  • В JDK <9 в среде выполнения Java видны только классы в корневой записи.
  • На JDK 9 классы A и B будут загружены из root/META-INF/versions/9 каталога root/META-INF/versions/9 , а C и D будут загружены из базовой записи.
  • На JDK 10 класс A будет загружен из каталога root/META-INF/versions/10 .

Создание многодисковой банки с использованием инструмента банки

Команда jar может использоваться для создания многоэкранного Jar, содержащего две версии одного и того же класса, скомпилированные как для Java 8, так и для Java 9, хотя и с предупреждением о том, что классы идентичны:

C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demo
Warning: entry META-INF/versions/9/demo/SampleClass.class contains a class that
is identical to an entry already in the jar

Параметр --release 9 указывает jar включить все, что следует ( demo пакет внутри sampleproject-9 ) внутри root/META-INF/versions/9 с версией в MRJAR, а именно под root/META-INF/versions/9 . Результатом является следующее содержание:

jar root
  - demo
     - SampleClass.class
  - META-INF
     - versions
        - 9
           - demo
              - SampleClass.class

Давайте теперь создадим класс Main, который печатает URL-адрес SampleClass и добавляет его для версии Java 9:

package demo;

import java.net.URL;

public class Main {

    public static void main(String[] args) throws Exception {
        URL url = Main.class.getClassLoader().getResource("demo/SampleClass.class");
        System.out.println(url);
    }
}

Если мы скомпилируем этот класс и запустим команду jar, мы получим сообщение об ошибке:

C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demoentry: META-INF/versions/9/demo/Main.class, contains a new public class not found in base entries
Warning: entry META-INF/versions/9/demo/Main.java, multiple resources with same name
Warning: entry META-INF/versions/9/demo/SampleClass.class contains a class that
is identical to an entry already in the jar
invalid multi-release jar file MR.jar deleted

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

Чтобы добавить Main в корневую запись, нам сначала нужно скомпилировать ее для таргетинга на версию до 9 Java. Это можно сделать с помощью новой опции --release javac :

C:\Users\manouti\sampleproject-base\demo>javac --release 8 Main.java
C:\Users\manouti\sampleproject-base\demo>cd ../..
C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demo

Запуск основного класса показывает, что SampleClass загружается из каталога версий:

C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class

URL загруженного класса внутри многоэкранного Jar

Учитывая следующий многорежимный Jar:

jar root
  - demo
     - SampleClass.class
  - META-INF
     - versions
        - 9
           - demo
              - SampleClass.class

Следующий класс печатает URL-адрес SampleClass :

package demo;

import java.net.URL;

public class Main {

    public static void main(String[] args) throws Exception {
        URL url = Main.class.getClassLoader().getResource("demo/SampleClass.class");
        System.out.println(url);
    }
}

Если класс скомпилирован и добавлен в версию для версии Java 9 в MRJAR, ее запуск приведет к:

C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow