Modulare JARs und Runtimes

Java 9 Bootcamp Logo

Im ersten zweiten und dritten Teil dieser Serie habe ich gezeigt, wie man Module baut, Abhängigkeiten zwischen ihnen setzt und wie man lose gekoppelte Serviceabhängigkeiten herstellt. Jetzt verpacken wir unsere drei Module und bauen eine angepasste Runtime.

Modulare JARs

Module werden nach wie vor als JAR verpackt. Neu ist lediglich, dass im Wurzelverzeichnis des Archives eine module-info Klasse liegt. Erzeugen Sie zunächst ein Zielverzeichnis ("dist")für die fertigen Module. Dann beginnen wir mit dem ersten Modul.

>jar --create --file=dist/de.eppleton.greetings@1.0.jar --module-version=1.0 -C modules/de.eppleton.greetings .
>jar --create --file=dist/de.eppleton.swinggreeter@1.0.jar --module-version=1.0 -C modules/de.eppleton.swinggreeter .
>jar --create --file=dist/de.eppleton.hello@1.0.jar --module-version=1.0 --main-class=de.eppleton.hello.HelloWorld -C modules/de.eppleton.hello .

Danach können Sie die Anwendung starten (-p ist die Kurzform von --module-path):

java -p dist -m de.eppleton.hello

Die modulare Runtime

In unserer Anwendung verwenden wir lediglich die Module java.base und java.desktop. Wenn wir die Anwendung nun ausliefern, reicht es diese Module mitzugeben. Wir verwenden dafür das jlink tool:

>jlink --module-path $JAVA_HOME/jmods:dist --add-modules de.eppleton.hello --output helloapp 

Mit "--module-path" geben wir an, wo die Java-Basismodule liegen. Der Parameter "--add-modules" fügt unser Hauptmodul und alle transitiven Abhängigkeiten hinzu und output gibt das Zielverzeichnis an.

Das Ergebnis ist also das Verzeichnis "helloapp":

.
|____bin
| |____java
| |____keytool
|____conf
| |____net.properties
| |____security
| | |____java.policy
| | |____java.security
| | |____policy
| | | |____limited
| | | | |____default_local.policy
| | | | |____default_US_export.policy
| | | | |____exempt_local.policy
| | | |____README.txt
| | | |____unlimited
| | | | |____default_local.policy
| | | | |____default_US_export.policy
|____include
| |____classfile_constants.h
| |____darwin
| | |____jni_md.h
| |____jni.h
| |____jvmti.h
| |____jvmticmlr.h
|____legal
| |____java.base
| | |____aes.md
| | |____asm.md
| | |____cldr.md
| | |____COPYRIGHT
| | |____icu.md
| | |____public_suffix.md
| | |____zlib.md
|____lib
| |____classlist
| |____jli
| | |____libjli.dylib
| |____jrt-fs.jar
| |____jspawnhelper
| |____jvm.cfg
| |____libjava.dylib
| |____libjimage.dylib
| |____libjsig.dylib
| |____libnet.dylib
| |____libnio.dylib
| |____libosxsecurity.dylib
| |____libverify.dylib
| |____libzip.dylib
| |____modules
| |____security
| | |____blacklist
| | |____blacklisted.certs
| | |____cacerts
| | |____default.policy
| | |____public_suffix_list.dat
| | |____trusted.libraries
| |____server
| | |____libjsig.dylib
| | |____libjvm.dylib
| | |____Xusage.txt
| |____tzdb.dat
|____release

Mit dem Aufrufparameter "--list-modules" können Sie die enthaltenen Module ausgeben:

>./bin/java -list-modules 
de.eppleton.greetings@1.0
de.eppleton.hello@1.0
java.base@9-ea

Fällt Ihnen etwas auf? Das Programm wird so nicht funktionieren. Es fehlt das Modul "de.eppeton.swinggreetings" und auch "java.desktop" ist nicht dabei.

Das liegt an der losen Kopplung, die wir im Teil 3 des Tutorials verwendet haben. Wir haben lediglich das Hauptmodul und seine transitiven Abhängigkeiten. Das lose gekoppelte Modul "de.eppleton.swinggreeter" ist nicht mit dabei. Wir müssen es explizit angeben. Löschen wir also das Verzeichnis helloapp und versuchen wir es noch einmal:

>jlink --module-path $JAVA_HOME/jmods:dist --add-modules de.eppleton.hello,de.eppleton.swinggreeter --output helloapp
>./helloapp/bin/java --list-modules
de.eppleton.greetings@1.0
de.eppleton.hello@1.0
de.eppleton.swinggreeter@1.0
java.base@9-ea
java.datatransfer@9-ea
java.desktop@9-ea
java.prefs@9-ea
java.xml@9-ea

Diesmal ist alles mit dabei, auch das Modul java.desktop und dessen Abhängigkeiten. Nun können Sie die Anwnedung starten:

 >./helloapp/bin/java --module de.eppleton.hello

Die Runtime ist nun 78,7 MB groß. Das jlink-Tool verfügt aber über weitere Funktionen, mit denen sich die Runtime noch stärker verkleinern lässt:

 >jlink --module-path $JAVA_HOME/jmods:dist --add-modules de.eppleton.hello,de.eppleton.swinggreeter --output helloapp --exclude-files *.diz --strip-debug --compress=2 --no-header-files --no-man-pages

Danach ist die Runtime nur noch 41,6 MB groß, ohne das Modul java.desktop und dessen Abhängigkeiten könnten wir noch einmal circa 20 MB einsparen. Eine weitere interessante Funktion ist das Erzeugen eines Launchers mit diesem zusätzlichen Aufrufparameter:

--launcher helloworld=de.eppleton.hello

Danach befindet im bin-Verzeichnis ein ausführbarer Launcher, und Sie können die Anwendung direkt damit starten:

> ./helloapp/bin/helloworld 

Das ist ein sehr praktisches Feature für die Auslieferung von Java Anwendungen.

Besuchen Sie unsere Workshops zum Thema Java 9 um mehr über dieses und weitere neue Features von Java 9 zu erfahren: