Java Language
JAR-Dateien mit mehreren Versionen
Suche…
Einführung
Eine der in Java 9 eingeführten Funktionen ist die Multi-Release-Jar (MRJAR), die die Bündelung von Code für mehrere Java-Releases in derselben Jar-Datei ermöglicht. Die Funktion ist in JEP 238 angegeben .
Beispiel für den Inhalt einer Jar-Datei mit mehreren Versionen
Durch Festlegen von Multi-Release: true
in der MANIFEST.MF-Datei wird die Jar-Datei zu einer Multi-Release-Jar und die Java-Laufzeitumgebung (sofern das MRJAR-Format unterstützt wird) wählt die entsprechenden Klassenversionen abhängig von der aktuellen Hauptversion aus .
Die Struktur eines solchen Bechers ist wie folgt:
jar root
- A.class
- B.class
- C.class
- D.class
- META-INF
- versions
- 9
- A.class
- B.class
- 10
- A.class
- Bei JDKs <9 sind nur die Klassen im Root-Eintrag für die Java-Laufzeitumgebung sichtbar.
- Auf einem JDK 9 werden die Klassen A und B aus dem Verzeichnis
root/META-INF/versions/9
geladen, während C und D aus dem Basiseintrag geladen werden. - Auf einem JDK 10 wird Klasse A aus dem Verzeichnis
root/META-INF/versions/10
geladen.
Ein Mehrfach-Release-Jar mit dem Jar-Tool erstellen
Mit dem Befehl jar
können Sie eine Jar-Version mit mehreren Versionen erstellen, die zwei Versionen derselben Klasse enthält, die sowohl für Java 8 als auch für Java 9 kompiliert wurden. Die Warnung gibt jedoch an, dass die Klassen identisch sind:
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
Die Option --release 9
weist jar
an, alles, was folgt (das demo
Paket im sampleproject-9
), in einen versionierten Eintrag in der MRJAR aufzunehmen, und zwar unter root/META-INF/versions/9
. Das Ergebnis ist folgender Inhalt:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Lassen Sie uns nun eine Klasse namens Main erstellen, die die URL der SampleClass
, und fügen Sie sie für die Java 9-Version hinzu:
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);
}
}
Wenn wir diese Klasse kompilieren und den JAR-Befehl erneut ausführen, wird ein Fehler angezeigt:
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
Der Grund ist, dass das jar
Tool das Hinzufügen öffentlicher Klassen zu versionierten Einträgen verhindert, wenn diese nicht ebenfalls zu den Basiseinträgen hinzugefügt werden. Dies geschieht, damit der MRJAR dieselbe öffentliche API für die verschiedenen Java-Versionen verfügbar macht. Beachten Sie, dass diese Regel zur Laufzeit nicht erforderlich ist. Es kann nur von Werkzeugen wie dem jar
angewendet werden. In diesem speziellen Fall besteht der Zweck von Main
darin, Beispielcode auszuführen, sodass wir einfach eine Kopie im Basiseintrag hinzufügen können. Wenn die Klasse Teil einer neueren Implementierung war, die wir nur für Java 9 benötigen, könnte sie nicht öffentlich gemacht werden.
Um Main
zum Root-Eintrag hinzuzufügen, müssen wir ihn zunächst für ein Pre-Java 9-Release kompilieren. Dies kann mit der neuen Option --release
von 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
Das Ausführen der Main-Klasse zeigt, dass die SampleClass aus dem versionierten Verzeichnis geladen wird:
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 einer geladenen Klasse in einer Jar mit mehreren Versionen
Angesichts der folgenden Multi-Release-Jar:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Die folgende Klasse druckt die URL der 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);
}
}
Wenn die Klasse kompiliert und zu dem versionierten Eintrag für Java 9 in der MRJAR hinzugefügt wird, führt das Ausführen zu folgendem Ergebnis:
C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class