Java Language
Multi-Release JAR-filer
Sök…
Introduktion
En av funktionerna som introducerats i Java 9 är multi-release Jar (MRJAR) som tillåter paketkod som är inriktad på flera Java-releaser i samma Jar-fil. Funktionen anges i JEP 238 .
Exempel på innehållet i en Jar-fil med flera släpp
Genom att ställa in Multi-Release: true
i MANIFEST.MF-filen blir Jar-filen en multi-release Jar och Java-runtime (så länge den stöder MRJAR-formatet) kommer att välja lämpliga versioner av klasser beroende på den aktuella större versionen .
Strukturen för en sådan burk är följande:
jar root
- A.class
- B.class
- C.class
- D.class
- META-INF
- versions
- 9
- A.class
- B.class
- 10
- A.class
- På JDK: er <9 är det bara klasserna i rotposten som är synliga för Java-runtime.
- På en JDK 9 kommer klasserna A och B att laddas från
root/META-INF/versions/9
, medan C och D kommer att laddas från basposten. - På en JDK 10 laddas klass A från
root/META-INF/versions/10
.
Skapa en burk med flera frisättningar med hjälp av burkverktyget
jar
kommandot kan användas för att skapa en multi-release jar som innehåller två versioner av samma klass sammanställd för både Java 8 och Java 9, om än med en varning som säger att klasserna är identiska:
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
Den --release 9
alternativet anger jar
till att omfatta allt som följer (den demo
paket inne i sampleproject-9
katalog) i en versions post i MRJAR, nämligen enligt root/META-INF/versions/9
. Resultatet är följande innehåll:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Låt oss nu skapa en klass som heter Main som skriver ut URL: en för SampleClass
och lägger till den för Java 9-versionen:
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);
}
}
Om vi sammanställer denna klass och kör igen jar-kommandot får vi ett fel:
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
Anledningen är att jar
förhindrar att offentliga klasser läggs till i versionerade poster om de inte också läggs till i basposterna. Detta görs så att MRJAR exponerar samma offentliga API för de olika Java-versionerna. Observera att vid körning krävs inte denna regel. Det får bara användas av verktyg som jar
. I det här fallet är syftet med Main
att köra provkod, så att vi helt enkelt kan lägga till en kopia i basposten. Om klassen var en del av en nyare implementering som vi bara behöver för Java 9, skulle den kunna göras icke-offentlig.
För att lägga till Main
till rotposten måste vi först kompilera den för att rikta in en pre-Java 9-version. Detta kan göras med hjälp av den nya --release
alternativet 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
Att köra huvudklassen visar att SampleClass laddas från den versionerade katalogen:
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 till en laddad klass i en flersläppande burk
Följande flaska med flera släpp:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Följande klass skriver ut URL: en för 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);
}
}
Om klassen kompileras och läggs till i den versionerade posten för Java 9 i MRJAR, skulle den köra resultera i:
C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class