Java Language
JAR-bestanden met meerdere releases
Zoeken…
Invoering
Een van de functies die is geïntroduceerd in Java 9 is de multi-release Jar (MRJAR) waarmee code kan worden gebundeld die is gericht op meerdere Java-releases binnen hetzelfde Jar-bestand. De functie is gespecificeerd in JEP 238 .
Voorbeeld van de inhoud van een Jar-bestand met meerdere releases
Door Multi-Release: true
in het MANIFEST.MF-bestand in te stellen, wordt het Jar-bestand een multi-release Jar en kiest de Java-runtime (zolang het de MRJAR-indeling ondersteunt) de juiste klassenversies, afhankelijk van de huidige hoofdversie .
De structuur van zo'n pot is als volgt:
jar root
- A.class
- B.class
- C.class
- D.class
- META-INF
- versions
- 9
- A.class
- B.class
- 10
- A.class
- Op JDK's <9 zijn alleen de klassen in het root-item zichtbaar voor de Java-runtime.
- Op een JDK 9 worden de klassen A en B geladen vanuit de map
root/META-INF/versions/9
, terwijl C en D worden geladen vanuit het basisitem. - Op een JDK 10 zou klasse A worden geladen vanuit de directory
root/META-INF/versions/10
.
Een multi-release jar maken met behulp van de jar-tool
Het jar
commando kan worden gebruikt om een multi-release jar te maken met twee versies van dezelfde klasse die zijn gecompileerd voor zowel Java 8 als Java 9, zij het met een waarschuwing dat de klassen identiek zijn:
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
De --release 9
optie vertelt jar
om alles wat volgt (de include demo
-pakket in de sampleproject-9
directory) in een versioned vermelding in de MRJAR, namelijk onder root/META-INF/versions/9
. Het resultaat is de volgende inhoud:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Laten we nu een klasse maken met de naam Main die de URL van de SampleClass
en deze toevoegen voor de Java 9-versie:
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);
}
}
Als we deze klasse compileren en het jar-commando opnieuw uitvoeren, krijgen we een foutmelding:
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
De reden is dat de jar
tool voorkomt dat openbare klassen worden toegevoegd aan ingevoerde versies als deze niet ook aan de basisitems worden toegevoegd. Dit wordt gedaan zodat de MRJAR dezelfde openbare API voor de verschillende Java-versies blootstelt. Merk op dat deze regel tijdens runtime niet vereist is. Het kan alleen worden toegepast door hulpmiddelen zoals jar
. In dit specifieke geval is het doel van Main
om voorbeeldcode uit te voeren, dus we kunnen eenvoudig een kopie toevoegen aan het basisitem. Als de klasse deel uitmaakte van een nieuwere implementatie die we alleen voor Java 9 nodig hebben, zou deze klasse niet-openbaar kunnen worden gemaakt.
Om Main
aan het root-item toe te voegen, moeten we het eerst compileren om een pre-Java 9-release te targeten. Dit kan met de nieuwe --release
optie van 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
Het uitvoeren van de klasse Main laat zien dat de SampleClass wordt geladen vanuit de versiemap:
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 van een geladen klasse in een multi-release jar
Gegeven de volgende multi-release Jar:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
De volgende klasse drukt de URL van de 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);
}
}
Als de klasse wordt gecompileerd en toegevoegd aan het versie-item voor Java 9 in de MRJAR, zou het uitvoeren:
C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class