Szukaj…


Wprowadzenie

Jedną z funkcji wprowadzonych w Javie 9 jest wielodostępny jar (MRJAR), który pozwala na wiązanie kodu ukierunkowanego na wiele wydań Java w tym samym pliku Jar. Ta funkcja jest określona w JEP 238 .

Przykład zawartości pliku jar wielu wersji

Ustawiając opcję Multi-Release: true w pliku MANIFEST.MF, plik Jar staje się wersją Jar wielokrotnego wydania, a środowisko wykonawcze Java (o ile obsługuje format MRJAR) wybiera odpowiednie wersje klas w zależności od bieżącej wersji głównej .

Struktura takiego słoika jest następująca:

jar root
  - A.class
  - B.class
  - C.class
  - D.class
  - META-INF
     - versions
        - 9
           - A.class
           - B.class
        - 10
           - A.class
  • W JDK <9 tylko klasy we wpisie root są widoczne dla środowiska wykonawczego Java.
  • W JDK 9 klasy A i B zostaną załadowane z katalogu root/META-INF/versions/9 , natomiast C i D zostaną załadowane z pozycji podstawowej.
  • Na JDK 10 klasa A byłaby ładowana z katalogu root/META-INF/versions/10 .

Tworzenie słoika z wieloma wersjami za pomocą narzędzia jar

Komendy jar można użyć do utworzenia jar z wieloma wydaniami, zawierającego dwie wersje tej samej klasy skompilowanej dla Java 8 i Java 9, aczkolwiek z ostrzeżeniem informującym, że klasy są identyczne:

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 opcja mówi jar na to wszystko, co się następująco (w demo pakiet wewnątrz sampleproject-9 Directory) wewnątrz wersjonowanym wpisu w MRJAR, mianowicie pod root/META-INF/versions/9 . Wynikiem jest następująca zawartość:

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

Utwórzmy teraz klasę o nazwie Main, która wypisuje adres URL klasy SampleClass i dodamy ją dla wersji 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);
    }
}

Jeśli skompilujemy tę klasę i ponownie uruchomimy komendę jar, otrzymamy błąd:

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

Powodem jest to, że narzędzie jar zapobiega dodawaniu klas publicznych do wpisów wersjonowanych, jeśli nie są one również dodawane do wpisów podstawowych. Odbywa się to tak, że MRJAR udostępnia ten sam publiczny interfejs API dla różnych wersji Java. Należy pamiętać, że w czasie wykonywania ta reguła nie jest wymagana. Może być nakładany tylko za pomocą narzędzi takich jak jar . W tym konkretnym przypadku, celem Main jest uruchomienie przykładowego kodu, więc możemy po prostu dodać kopię w pozycji bazowej. Gdyby klasa była częścią nowszej implementacji, której potrzebujemy tylko w Javie 9, mogłaby być niepubliczna.

Aby dodać Main do wpisu root, najpierw musimy go skompilować w celu wydania wersji wcześniejszej niż Java 9. Można to zrobić za pomocą nowej opcji --release w 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

Uruchomienie klasy Main pokazuje, że SampleClass jest ładowany z katalogu wersji:

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

Adres URL załadowanej klasy wewnątrz jar z wieloma wydaniami

Biorąc pod uwagę następujący słoik z wieloma wersjami:

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

Następująca klasa wypisuje adres URL klasy 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);
    }
}

Jeśli klasa zostanie skompilowana i dodana do wersjonowanej pozycji dla Java 9 w MRJAR, uruchomienie jej spowoduje:

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow