Suche
Die Stichsäge kommt voran

JDK 9 und die Plattformmodularisierung: So funktioniert Projekt Jigsaw

Wolfgang Weigend
Java-Magazin-1-16_Aufmacher_Weigend_istock_Nikola_Nastasic_900x600

© iStock / Nikola Nastasic

Das für März 2017 geplante Release von JDK 9 soll den lang ersehnten modularen Aufbau der Java SE enthalten. Damit ist es künftig möglich, die technische Paketierung von ausgewählter Java-Funktionalität selbst zu bestimmen. Dafür müssen Entwickler aber genau wissen, wie Module erstellt und kompiliert werden.

Das Projekt Jigsaw hat die primäre Aufgabe, das Design und die Implementierung eines Standardmodulsystems für die Java-Plattform und für das JDK 9 bereitzustellen. Jigsaw soll außerdem berücksichtigen, dass sich die Java-SE-Plattform und das JDK auch für kleine Endgeräte durchgängig, dynamisch und einfach anpassen lassen. Zudem soll die Sicherheit und Wartbarkeit von Java-SE-Plattform-Implementierungen und vom JDK verbessert werden. Insbesondere sind die Probleme beim Umgang mit dem Classpath und dem monolithischen JDK abzuschaffen.

Mit drei JDK Enhancement Proposals (JEPs) wurden Basisvorschläge für die JDK-Modularität gemacht: modulare JDK-Struktur (JEP 200 – The Modular JDK), modulare Reorganisation vom JDK-Sourcecode (JEP 201 – Modular Source Code), Restrukturierung von JDK- und JRE-Laufzeit-Images (JEP 220 – Modular Run-Time Images). Die Java-SE-9-Spezifikationsanforderung (JSR 376: Java Platform Module System) spezifiert das gesamte Modulsystem für die Java-SE-Plattform.

Modulares JDK (JEP 200): JDK modular aufspalten

Bei der Definition der modularen JDK-Struktur verfolgt man das Ziel, das JDK in verschiedene Module aufzuspalten, die zur Kompilation für Build und Installation oder in unterschiedlichen Laufzeitkonfigurationen wieder zusammengefügt werden können. Die Modulkonfigurationen korrespondieren jeweils mit der vollständigen Java-SE-Plattform, der kompletten JRE und dem gesamten JDK. Zudem sind die Konfigurationen inhaltlich nahezu gleichwertig mit den drei Compact-Profilen der Java SE 8. Eigene Konfigurationen enthalten lediglich einen Modulsatz und durchgereichte Modulanforderungen. Die Modulstrukturdefinition unterscheidet zwischen Standardmodulen, deren Spezifikationen der Java Community Process (JCP) überwacht, und solchen Modulen, die spezifisch für das JDK sind. Außerdem werden Module unterschieden, die in die Java-SE-Plattformspezifikation einbezogen werden und damit für jede Plattformimplementierung obligatorisch sind. Zur Umsetzung des Modulsystemvorschlags wurden folgende Annahmen getroffen:

  • Ein Modul enthält Java-Klassendateien, Ressourcen, abhängige native Bibliotheken und Konfigurationsdateien.
  • Jedes Modul trägt einen Namen.
  • Ein Modul kann von einem oder mehreren anderen Modulen abhängig sein.
  • Ein Modul kann alle Public-Typen in ein oder mehrere API-Packages exportieren, das darin enthalten ist. Damit werden die Typen für abhängigen Modulcode nutzbar gemacht und auch für Kodierungen, die nicht in jedem Modul verwendet werden.
  • Die Einschränkung von Modulen geschieht über den Namen und über die Modulgruppe, in die die Public-Typen und deren API-Packages exportiert werden. Dies ermöglicht den Modulen, ihre internen Implementierungsinterfaces weiterzureichen, ohne dabei diese Interfaces allen anderen Kodierungen zeigen zu müssen.
  • Ein Modul kann die Public-Typen weiterexportieren, die von einem oder mehreren Modulen exportiert wurden und davon abhängig sind. Dadurch können Module nach einer bestimmten Zeit umgestaltet werden und die exportierten Public-Type-Gruppen dabei erhalten bleiben. Dazu werden Aggregator-Moduldefinitionen angeboten, die alle exportierten Public-Typen von abhängigen Modulgruppen aufsammeln können.

Die vorgeschlagene Modulstruktur unterliegt folgenden Implementierungsrichtlinien:

  • Die Namen von Standardmodulen müssen mit der Zeichenkette java. beginnen, und alle anderen im JDK enthaltenen Module müssen mit der Zeichenkette jdk. beginnen.
  • Falls ein Modul einen Typ exportiert, der einen Public oder Protected Member enthält, der wiederum auf den Typ eines anderen Moduls verweist, so muss das erste Modul den Public Type vom zweiten Modul wieder exportieren. Dadurch wird die Arbeitsweise einer Method-Invocation-Kette sichergestellt.
  • Ein Standardmodul kann Standard- und Non-Standard-API-Packages enthalten und beliebige Standard-API-Packages ohne Beschränkungen exportieren. Der Export von API-Packages kann auch zu einer Auswahl von Standard- und Non-Standard-Modulen erfolgen. Im Umkehrschluss müssen aber keine Non-Standard-API-Packages exportiert werden. Falls ein Java-SE-Modul verwendet wird, um es beispielsweise als Vorschlag in die Java-SE-Plattformspezifikation einzubinden, muss es keine Non-SE-API-Packages exportieren.
  • Ein Standardmodul kann von einem oder mehreren anderen Standardmodulen abhängen und es muss keine Public-Typen von Non-SE-Modulen wieder rückexportieren. Falls ein Java-SE-Modul vorliegt, muss es keine Public-Typen von Non-SE-Modulen reexportieren. Aus dieser und der vorangegangenen Richtlinie ergibt sich die Konsequenz, dass Code, der nur von Java-SE-Modulen abhängt, auch nur von Java-SE-Typen abhängig ist und damit für alle Java-SE-Plattformimplementierungen portierbar ist.
  • Ein Non-Standardmodul muss keine Standard-API-Packages exportieren und es darf die Public-Typen, die von einem Standardmodul exportiert wurden, wieder reexportieren.

JDK-Modulgraph visualisiert Module

Die modulare JDK-Struktur kann als Graph visualisiert werden. Dabei wird jedes Modul als Knoten dargestellt. Mit einem vollständigen Graph wird jeder Modulknoten mit einem anderen Modulknoten durch eine Kante verbunden, wenn das erste Modul vom zweiten Modul abhängt. Der komplette Modulgraph hat zu viele Kanten, um sie noch übersichtlich darstellen zu können. Deshalb werden die redundanten Kanten durch transitive Reduktion vom Modulgraph ausgelassen.

weigend_jigsaw_1

Abb. 1: JDK-Modulgraph visualisiert jedes Modul als Knoten

Die Java-SE-Module sind mit der Farbe Orange dargestellt und die Non-SE-Module mit blauer Farbe. Falls ein Modul von einem anderen Modul abhängt und dessen Public-Typen reexportiert, ist die Kante vom ersten zum zweiten Modul dunkel. Im umgekehrten Fall ist die Kante heller. An der Unterseite befindet sich das Modul java.base mit essenziellen Klassen wie java.lang.Object und java.lang.String. Das Base-Modul hängt von keinem Modul ab, und alle anderen Module sind vom Base-Modul abhängig. An der Oberseite befindet sich das Modul java.se. Es umfasst alle Module der Java-SE-Plattform und ist ein Beispiel eines Aggregatormoduls, das die Reexporte und Inhalte von anderen Modulen aufsammelt, aber keine eigenen Inhalte hinzufügt. Ein konfiguriertes Laufzeitsystem mit dem Modul java.se enthält auch alle Java-SE-Plattform-API-Packages. Ein Modul wird nur dann als Vorschlag zur Java-SE-Plattformspezifikation hinzugefügt, wenn es sich um ein Standardmodul handelt, das vom java.se-Modul auch erreichbar ist. Die Aggregatormodule java.compact1, java.compact2, und java.compact3 implementieren die Java-SE-Compact-Profile. Es existiert auch ein Non-Standard-Modul jdk.compact3, weil ein compact3 JDK Build einige Non-SE-API-Packages enthält, die in den anderen Compact Profile Builds nicht enthalten sind.

Die anderen Non-Standard-Module enthalten Debugger- und Servicewerkzeuge sowie APIs wie jdk.jdi, jdk.jcmd und jdk.jconsole in der oberen linken Diagrammhälfte. Die Entwicklungswerkzeuge jdk.compiler, jdk.javadoc und jdk.xml.bind sind in der oberen rechten Diagrammhälfte dargestellt. Andere Service-Provider, wie jdk.charsets, jdk.scripting.nashorn und jdk.crypto.ec, werden über die Konvention java.util.ServiceLoader den anderen Modulen zugänglich gemacht. Der Modulgraph ist praktisch eine Art Schnittstelle und wird auch als solche spezifiziert und erweitert. Der Graph, der unterhalb vom Graphmodul java.se liegt, bei dem alle Non-SE-Module und korrespondierenden Kanten entfernt wurden, wird zur Aufnahme in die Java-SE-Plattformspezifikation vorgeschlagen und die Weiterentwicklung über den Java-Community-Prozess gesteuert. Die Fortentwicklung vom restlichen Graphen wird durch künftige JDK Enhancement Proposals abgedeckt. Wird ein Modul so spezifiziert, dass es allgemein verwendet werden kann, unterliegt es in jedem Fall den gleichen evolutionären Beschränkungen wie andere APIs. Werden solche Module entfernt oder inkompatibel verändert, so erfordert dies eine öffentliche Benachrichtigung für ein Hauptrelease im Voraus.

Modularer Quell-Code (JEP 201): Quellcode komplett umstrukturieren

Durch die modulare Reorganisation vom JDK-Sourcecode, der Build-Systemverbesserung zum Kompilieren von Modulen und mit einer erzwungenen Modulabgrenzung zum Build-Zeitpunkt wird die existierende JDK-Quellcodeorganisation komplett neu gestaltet. Das neue Schema des modularen JDKs nutzt die seltene Gelegenheit einer kompletten Quellcodeumstrukturierung, um die Wartung zu vereinfachen. Der Implementierungsvorschlag sieht das Schema in jedem JDK Forest Repository vor, mit Ausnahme der Java HotSpot VM. Das Schema sieht in Kurzform wie folgt aus:

src/$MODULE/{share,$OS}/classes/$PACKAGE/*.java
                        native/include/*.{h,hpp}
                               $LIBRARY/*.{c,cpp}
                        conf/*
  • $MODULE ist der Modulname (z. B. java.base).
  • Das Verzeichnis share enthält, wie zuvor, verteilte und plattformübergreifende Kodierungen.
  • Das Verzeichnis $OS enthält betriebssystemspezifische Kodierungen und steht für die Betriebssysteme Unix, Windows etc.
  • Das Verzeichnis classes enthält die Java-Quell- und Ressourcedateien, die im Verzeichnisbaum strukturiert sind, inklusive ihrer API-$PACKAGE-Hierarchie.
  • Das Verzeichnis native enthält C- oder C++-Quelldateien, wie zuvor, aber mit unterschiedlicher Organisationsstruktur: Das Verzeichnis include enthält C- oder C++-Header-Dateien, die für externe Anwendungen exportiert werden können (z. B. jni.h). Die C- oder C++-Quelldateien, die als Shared Library oder DLL bezeichnet werden und in die kompilierter Code gelinkt werden, sind im Verzeichnis $LIBRARY enthalten (z. B. libjava oder libawt).
  • Das Verzeichnis conf enthält Konfigurationsdateien, die der Benutzer editieren kann (z. B. net.properties).

Build-Systemänderungen: Module zu einem Zeitpunkt kompilieren

Das Build-System wird so verändert, dass ein Modul zu einem Zeitpunkt kompiliert werden kann, im Gegensatz zu einem Repository. Die Module werden passend zur umgekehrten Anordnungsreihenfolge vom Modulgraphen kompiliert. Unabhängige Module werden nach Möglichkeit gleichzeitig kompiliert. Der Nebeneffekt einer Modulkompilierung, im Gegensatz zu den Repositories, besteht darin, dass der Repository-Code von corba, jaxp und jaxws neue Java-Sprachmerkmale und APIs verwenden kann. Das war bislang nicht zulässig, da diese Repositories vor dem JDK Repository kompiliert wurden. Die kompilierten Klassen in einem Interims-Build (Non-Image) werden in Module aufgeteilt. Dann wird aus jdk/classes/*.class im überarbeiteten Build-System jdk/modules/$MODULE/*.class erzeugt. Die Image-Build-Struktur wird nicht verändert, und es wird nur minimale inhaltliche Unterschiede geben. Die Modulgrenzen werden bestenfalls vom Build-System zum Build-Zeitpunkt gesetzt. Falls Modulabgrenzungen verletzt werden, schlägt der Build-Lauf fehl. Mit der Konfigurationsdatei modules.xml werden die Abgrenzungen definiert und neben dem Quellcode gewartet. Dateiänderungen verlangen eine Überprüfung der Projekt-Committer von Jigsaw.

Modulare Laufzeit-Images (JEP 220)

Der Vorschlag besteht aus der Umstrukturierung von JDK und JRE-Laufzeit-Images in passende Module und der Verbesserung von Geschwindigkeit, Sicherheit und Wartbarkeit. Zur Namensgebung von Modulen, Klassen und Ressourcen, die im Laufzeit-Image gespeichert sind, soll ein neues URI-Schema definiert werden, ohne dabei die interne Struktur oder das Image-Format offenzulegen. Vorhandene Spezifikationen sollen überarbeitet werden, um diese Änderungen zu erreichen. Dafür wurden im Anschluss diese Ziele gesetzt:

  • Schaffung eines Laufzeitformats zur Speicherung von Klassen- und Ressourcendateien mit den folgenden Eigenschaften: Es soll zeit- und platzsparender sein als das veraltete jar-Format, das auf dem zip-Format basiert. Es kann Klassen- und Ressourcendateien auf Modulebene lokalisieren und laden. Es kann Klassen- und Ressourcendateien speichern, die aus den Modulen vom JDK, Bibliotheken und Applikationen stammen.
  • Es kann zur Anpassung von zusätzlich anfallenden Daten erweitert werden, wie für vorab berechnete JVM-Datenstrukturen und präkompilierten nativen Code für Java-Klassen.
  • Restrukturierung vom JDK und JRE-Laufzeit-Images, um zu trennen, ob Dateien von Entwicklern, Deployment-Administratoren und Benutzern verwendet werden, die sie auch angemessen modifizieren können. Oder im Gegensatz dazu sollen interne Implementierungsdateien ohne Benachrichtigung geändert werden können.
  • Unterstützung zur Ausführung von gemeinsamen Operationen, die bislang nur mithilfe von internen Strukturuntersuchungen des Laufzeit-Images gemacht wurden, wie die Aufzählung aller vorhandenen Image-Klassen.
  • Bereitstellen einer selektiven Privilegienaufspaltung von JDK-Klassen, die bislang alle Sicherheitsberechtigungen besitzen, diese aber tatsächlich nicht benötigen.
  • Bewahrung der existierenden Verhaltensweise von mustergültigen Anwendungen, die beispielsweise von internen JRE- und JDK-Aspekten der Laufzeit-Images unabhängig sind.

Laufzeit-Image-Struktur: Trennung aufheben

Die bisherige Trennung von JRE und JDK ist historisch bedingt eine Konsequenz aus der späten Implementierungsentscheidung bei der Entwicklung vom JDK 1.2, die niemals überarbeitet wurde. Die neue Image-Struktur wird diese Trennung aufheben, und dann wird ein JDK-Image ein einfaches Laufzeit-Image sein, das den vollständigen Satz von Entwicklungswerkzeugen sowie andere historische JDK-Elemente enthalten wird. Das modulare Laufzeit-Image besitzt folgende Verzeichnisse:

  • Das Verzeichnis bin enthält jegliche Kommandozeilen-Launcher von den Modulen, die in das Image gebunden wurden. Für Windows werden weiterhin die zur Laufzeit dynamisch gebundenen nativen Bibliotheken enthalten sein.
  • Das Verzeichnis conf enthält die Dateien .properties, .policy und andere Dateiarten, die von Entwicklern, Deployment-Administratoren und Benutzern editiert werden können, die bislang im Verzeichnis lib und seinen Unterverzeichnissen zu finden waren.
  • Das Verzeichnis lib bei MAC OS oder das Verzeichnis lib/$ARCH bei Linux und Solaris wird die zur Laufzeit dynamisch gebundene native Bibliotheken enthalten. Sie können mit Programmen gelinkt werden, die über integrierte Laufzeitumsysteme verfügen.
  • Im Verzeichnis lib müssen alle anderen Dateien und Unterverzeichnisse als private Implementierungsdetails des Laufzeitsystems behandelt werden. Sie sind nicht zur externen Verwendung bestimmt, und deren Namen, Format und Inhalt kann ohne Ankündigung geändert werden.
  • Das vollständige JDK-Image enthält die Verzeichnisse demo, sample, man, und include.
  • Das Root-Verzeichnis vom modularen Laufzeit-Image wird die notwendigen Dateien COPYRIGHT, LICENSE, README, und RELEASE enthalten. Um festzustellen, welches Modul sich im Laufzeit-Image befindet, wird die Datei RELEASE mit der neuen Eigenschaft MODULES erweitert, die aus einer Modulnamenliste besteht, jeweils getrennt durch Leerzeichen. Die Liste wird topologisch angeordnet, passend zur den Modulabhängigkeitsbeziehungen, sodass das Modul java.base immer zuerst aufgelistet wird.

Ausgeschlossene Mechanismen und Bereiche

Der Java-Endorsed-Standards-Override-Mechanismus wird entfernt, wie bereits in der Java-SE-8-Dokumentation ersichtlich und im JEP 220 erwähnt wurde. Ein modulares Image besteht aus Modulen und weniger aus jar-Dateien. Künftig wird erwartet, dass die Endorsed-Standards und Standalone-APIs nur noch in modularer Form unterstützt werden, über das Upgradeable-Modules-Konzept. Falls ein JDK-Modul einen Endorsed-Standard oder ein Standalone-API implementiert, muss es möglich sein, eine Modulversion von einem späteren Release in beliebiger Phase zu verwenden, z. B. zum Compile-Zeitpunkt, zum Build-Zeitpunkt oder zur Laufzeit. Deshalb wird vorgeschlagen, das System-Property java.endorsed.dirs, das Verzeichnis lib/endorsed und die Codemechanismusimplementierung zu entfernen. Um festzustellen, wo dieser Mechanismus benutzt wurde, werden der Compiler und der Launcher so modifiziert, dass er fehlschlägt, wenn das SystemProperty gesetzt wurde oder das Verzeichnis lib/endorsed existiert.

Der Extension-Mechanismus zur Unterstützung von optionalen Packages wird ebenfalls entfernt, wie bereits in der Java-SE-8-Dokumentation ersichtlich und im JEP 220 erwähnt wurde. Einige nützliche Merkmale, die dem Extension-Mechanismus zugeordnet sind, bleiben dennoch bestehen:

  • Das Class-Path-Manifest-Attribut, das die jar-Dateienabhängigkeit untereinander spezifiziert.
  • Die Manifest-Attribute {Specification,Implementation}-{Title,Version,Vendor}, welche die Package- und die jar-Dateiversionsinformation spezifizieren.
  • Das Sealed-Manifest-Attribut, das ein Package oder eine jar-Datei versiegelt.
  • Der Extension Class Loader wird aus Kompatibilitätsgründen beibehalten.

Auch rt.jar und tools.jar werden entfernt. Die Klassen- und Ressourcendateien, die ehemals in lib/rt.jar, lib/tools.jar, lib/dt.jar und in zahlreichen anderen internen jar-Dateien gespeichert wurden, werden jetzt in einem besser geeigneten Format in implementierungsspezifischen Dateien im lib-Verzeichnis abgelegt. Das Dateiformat wird nicht weiter spezifiert und kann jederzeit geändert werden.

Java-Plattform-Modulsystem (JSR 376): Einfach und verständlich

Die Spezifikation definiert ein tragfähiges und skalierbares Modulsystem für die Java-Plattform. Es soll verständlich und einfach nutzbar sein, damit die Entwickler das Modulsystem zum Aufbau und der Wartung von Bibliotheken sowie für große Java-SE- und Java-EE-Anwendungen verwenden können. Die Skalierbarkeit steht im Vordergrund, damit sie zur Modularisierung der Java-SE-Plattform selbst beiträgt und für deren Implementierungen taugt. Das Einsatzgebiet von Java SE 9 umfasst Embedded-Geräte, Laptops, Desktops und Server. Existierende Spezifikationen, wie die Java-Language-Spezifikation (JLS), die Java-Virtual-Machine-Spezifikation (JVMS) und andere Elemente der Java-SE-Plattform-Spezifikation werden durch den JSR 376 überarbeitet und aktualisiert. Im Dokument „The State of the Module System – Initial Edition“ sind die Erweiterungen der Java-SE-Plattform mit dem Jigsaw-Prototyp von Mark Reinhold beschrieben und dienen als Einstiegspunkt für den JSR 376.

Jigsaw-Installation und -Werkzeuge

Das Project Jigsaw wurde zu diesem Zeitpunkt noch nicht mit dem JDK 9 zusammengeführt, sodass es bislang eigenständige JDK 9 Early Access Software Builds mit und ohne Jigsaw gibt. Das Release „JDK 9 Early Access with Project Jigsaw, build b83“ steht per Download und als zip-Datei für die Betriebssysteme Windows, OS X, Linux und Solaris zur Verfügung. Die Datei jigsaw-jdk-bin-windows-i586.zip für Windows 32 Bit muss in ein Verzeichnis entpackt werden und meldet sich wie folgt:

C:\projects\jdk1.9.0>java -version
java version "1.9.0-ea"
Java(TM) SE Runtime Environment (build 1.9.0-ea-jigsaw-nightly-h3477-20150929-b83)
Java HotSpot(TM) Client VM (build 1.9.0-ea-jigsaw-nightly-h3477-20150929-b83, mixed mode)

Vergleicht man das lib-Verzeichnis ..\jdk1.9.0\lib\modules mit der Version „JDK 9 EA Build 85“ und der Version „JDK 9 EA Jigsaw Build 83“, sind beim JDK 9 EA b85 im Pfad C:\Program Files (x86)\Java\jdk1.9.0\lib\modules die Modul-Images appmodules.jimage, bootmodules.jimage und extmodules.jimage enthalten. Beim JDK 9 EA Jigsaw b83 ist im Verzeichnis C:\projects\jdk1.9.0\lib\modules nur das Modul-Image bootmodules.jimage enthalten. Über das Werkzeug jimage werden die Klassendateien vom bootmodules.jimage im Pfad C:\projects\jdk1.9.0\lib\modules> angezeigt.

jimage list bootmodules.jimage |more und über die Eingabe jimage extract bootmodules.jimage -dir werden die Verzeichnisse mit den jeweils darin enthaltenen Dateien module-info.class in das frei wählbare Verzeichnis C:\projects\jdk1.9.0\mydir geschrieben (Kasten „Verzeichnisse vom bootmodules.jimage“).

Verzeichnisse vom bootmodules.jimage

  • java.activation
  • java.annotations.common
  • java.base
  • java.compact1
  • java.compact2
  • java.compact3
  • java.compiler
  • java.corba
  • java.datatransfer
  • java.desktop
  • java.instrument
  • java.logging
  • java.management
  • java.naming
  • java.prefs
  • java.rmi
  • java.scripting
  • java.se
  • java.security.jgss
  • java.security.sasl
  • java.smartcardio
  • java.sql
  • java.sql.rowset
  • java.transaction
  • java.xml
  • java.xml.bind
  • java.xml.crypto
  • java.xml.ws
  • javafx.base
  • javafx.controls
  • javafx.fxml
  • javafx.graphics
  • javafx.media
  • javafx.swing
  • javafx.web
  • jdk.accessibility
  • jdk.attach
  • jdk.charsets
  • jdk.compiler
  • jdk.crypto.ec
  • jdk.crypto.mscapi
  • jdk.crypto.pkcs11
  • jdk.deploy
  • jdk.hotspot.agent
  • jdk.httpserver
  • jdk.internal.le
  • jdk.internal.opt
  • jdk.jartool
  • jdk.javadoc
  • jdk.javaws
  • jdk.jcmd
  • jdk.jconsole
  • jdk.jdeps
  • jdk.jdi
  • jdk.jdwp.agent
  • jdk.jfr
  • jdk.jlink
  • jdk.jvmstat
  • jdk.localedata
  • jdk.management.cmm
  • jdk.naming.dns
  • jdk.naming.rmi
  • jdk.pack200
  • jdk.plugin
  • jdk.plugin.dom
  • jdk.policytool
  • jdk.rmic
  • jdk.scripting.nashorn
  • jdk.scripting.nashorn.shell
  • jdk.sctp
  • jdk.security.auth
  • jdk.security.jgss
  • jdk.snmp
  • jdk.xml.bind
  • jdk.xml.dom
  • jdk.xml.ws
  • jdk.zipfs

Mit dem jdeps-Werkzeug können die abhängigen Module aufgelistet werden, die eine besondere Classpath-Abhängigkeit besitzen. Diese Informationen werden gebraucht, um die benötigten Module automatisch zu bestimmen, die der Default-Einstellung entsprechen. Wird diese Erkennungsoption explizit ausgeschaltet, muss man stattdessen dem gesamten Image vertrauen oder einen eigenen Modulsatz spezifizieren. Das kommt nur dann zur Ausführung, wenn JMODs zur Laufzeit für den Java-Packager gebraucht werden. Unter dem provisorischen Begriff „JMOD“ versteht man ein neues künstliches Format, das über die Definition von jar-Dateien hinausgeht. Darin enthalten sind nativer Java-Code, Implementierungsdateien und andere anfallende Daten, die bislang nicht in jar-Dateien hineinpassten.

Schaut man sich die Modulklassenabhängigkeiten vom Verzeichnis java.desktop mit dem Java Class Dependency Analyzer jdeps an, so liefert jdeps -s eine Zusammenfassung der Abhängigkeiten:

C:\projects\jdk1.9.0\mydir>jdeps -s java.desktop
java.desktop -> java.base
java.desktop -> java.datatransfer
java.desktop -> java.prefs
java.desktop -> java.xml  

C:\projects\jdk1.9.0\mydir\java.desktop>jdeps -s module-info.class
module-info.class -> java.base
module-info.class -> java.datatransfer
module-info.class -> java.desktop

Mit dem Werkzeug jlink können JRE- und Applikations-Images generiert werden, beispielsweise ein JRE-Image, die nur die tatsächlich benötigten Module enthalten (Abb. 2 und JEP 275). Außerdem könnte jlink einige verborgene Verzahnungen für den eigenen Image-Erzeugungsprozess beisteuern. Dies kann zur individuellen Anpassung von Images vorteilhaft sein, beispielsweise könnte die Funktionalität „removal of executables“ für die jlink-Verarbeitung hinzugefügt werden. Der neue jlink-Prozess wird zur Erzeugung einer paketierten JRE verwendet, sobald die JDK-9-JMOD-Dateien für den Java-Packager verfügbar sind. Das jlink-Werkzeug enthält einen Plug-in- und Erweiterungsmechanismus. Über solch einen integrierten Mechanismus der jlink-Prozessausgabe wird ein korrektes und plattformspezifisches Layout vom Applikations-Image erzeugt. Dabei tritt der positive Nebeneffekt auf, dass die Applikations-Image-Generierung vom javapackager-Prozess unabhängig ist. Mit Jigsaw wird die Notation module path zusätzlich zum Classpath eingeführt. Neue Optionen und Konfigurationen werden zum Packer-API hinzugefügt, ein Ant-Plug-in und ein Command-Line-Interface (CLI), damit der Benutzer Module und Modulpfade zusätzlich zu jars und dem Klassenpfad spezifizieren kann.

weigend_jigsaw_2

Abb. 2: Mit dem Werkzeug jlink können JRE- und Applikations-Images generiert werden, die nur die tatsächlich benötigten Module enthalten

Im Dokument „Project Jigsaw: Module System Quick-Start Guide“ wird beispielhaft gezeigt, wie jlink verwendet wird. Dazu werden folgende Dateien unter C:\src angelegt, im Verzeichnis C:\mods dazu jeweils die Klassendateien module-info.class und main.class erzeugt und ausgeführt. Im Verzeichnis C:\mlib wird beispielhaft die jar-Datei erzeugt und dazu der Modul-Descriptor gezeigt.

C:\src\com.greetings\module-info.java

  module com.greetings { }

C:\src\com.greetings\com\greetings\Main.java

  package com.greetings;
  public class Main {
    public static void main(String[] args) {
      System.out.println("Greetings!");
    }
  }

C:\>javac -d mods/com.greetings src/com.greetings/module-info.java src/com.greetings/com/greetings/Main.java

C:\>java -modulepath mods -m com.greetings/com.greetings.Main
Greetings!

C:\>jar --create --file=mlib/com.greetings.jar --main-class=com.greetings.Main -C mods/com.greetings .

C:\mlib>java -jar com.greetings.jar
Greetings!

C:\mlib>jar --print-module-descriptor --file=com.greetings.jar

Name:		com.greetings
Requires:		java.base [ MANDATED ]
Main class:	com.greetings.Main
Conceals:		com.greetings

Das Werkzeug jlink bekommt über –modulpath die JDK-Module zugeführt, mit -addmods die eigenen Module und die Struktur wird über -output in ein frei wählbares Verzeichnis geschrieben. Das erzeugte Verzeichnis greetingsapp enthält die Unterverzeichnisse bin, conf, lib und die Datei RELEASE. Aus dem Modulpfad C:\projects\jdk1.9.0\jmods wurden die Module eingefügt und mit -addmods beispielhaft die Anwendungsdatei com.greetings hinzugefügt (Kasten: „Datei ‚RELEASE’“).

jlink <options> --modulepath <modulepath> --output <path>

C:\jlink --modulepath C:\projects\jdk1.9.0\jmods;mlib --addmods com.greetings --output greetingsapp

C:\greetingsapp>dir
Verzeichnis 	bin
Verzeichnis 	conf
Verzeichnis 	lib
Datei		release

Datei „RELEASE“

#Wed Nov 04 01:04:55 CET 2015

OS_VERSION=”5.1″

JAVA_VERSION=”1.9.0″

OS_NAME=”Windows”

SOURCE=” .\:d555d542bf37 bdb\:8ff6e91a0455 closed\:afcd0cf7a01d corba\:173fb1e5c13a deploy\:b900de8ea852 hotspot\:00ba345866f4 hotspot/make/closed\:5d3685711211 hotspot/src/closed\:882ef256dd2b hotspot/test/closed\:029f0900e2ef install\:4a2b8a2fe6f3 jaxp\:722eca4b78a2 jaxws\:49c4220a2a43 jdk\:deb77851e5fd jdk/make/closed\:06663e736525 jdk/src/closed\:b46ce6e7b2bd jdk/test/closed\:e529d90cdb63 langtools\:b40af8decd0b nashorn\:f9134ad4d147 pubs\:3f64773e6db7 sponsors\:12439cc89bb0″

OS_ARCH=”i586″

MODULES=jdk.charsets,java.rmi,java.security.sasl,java.datatransfer,java.prefs,
jdk.localedata,jdk.crypto.ec,jdk.naming.rmi,java.smartcardio,jdk.accessibility,
jdk.security.auth,com.greetings,java.xml.crypto,jdk.management,jdk.
management.cmm,jdk.naming.dns,java.base,java.logging,java.desktop,
java.naming,jdk.security.jgss,java.transaction,java.xml,java.corba,java.scripting,
jdk.deploy,jdk.zipfs,jdk.scripting.nashorn,jdk.crypto.pkcs11,jdk.crypt.mscapi,
java.management,java.security.jgss

Fazit und Ausblick

Die Modularisierung der Java-SE-Plattform im JDK 9 bringt viele Vorteile. Wohlgemerkt sind auch einige größere Änderungen damit verbunden. Existierender Anwendungscode, der nur offizielle Java-SE-Plattform-APIs mit den unterstützten JDK-spezifischen APIs verwendet, soll auch weiterhin ohne Änderungen ablauffähig sein. Nach wie vor ist die Abwärtskompatibilität für vorangegangene Hauptversionen mit Java SE gegeben, und das gilt auch für das künftige JDK-9-Release mit Jigsaw. Dennoch ist es wahrscheinlich, dass der Code unverträglich sein kann, wenn weiterhin veraltete Funktionalität oder JDK-interne APIs verwendet werden. Dafür können sich die Entwickler frühzeitig damit vertraut machen, wie existierende Bibliotheken und Anwendungen auf JDK 9 anzupassen sind, wie sie modularisiert werden, welche Designfragen zu klären sind und wie man vorhandenen Anwendungscode trotzdem mit JDK 9 zum Laufen bekommt, auch wenn man ihn nicht verändern kann.

Es ist ebenfalls notwendig zu untersuchen, wie das neue modulare JDK auf die Java-UI-Client-Anwendungen wie JavaFX reagiert. Die Verträglichkeit von JavaFX mit der Version „JDK 9 EA Jigsaw Build 83“ ist gegeben, sodass existierende JavaFX-Anwendungen mit kleineren Anpassungen auch mit dem künftigen JDK 9 arbeiten können.

Der Umgang mit dem künftigen JDK 9 erfordert Kenntnis darüber, wie die Modulerstellung gemacht wird, wie die Module kompiliert werden und viele notwendige Testläufe, damit es zu einer reibungslosen Inbetriebnahme von JDK-9-Anwendungen kommt. Jigsaw trennt die APIs und die Implementierung von Java-Komponenten und bietet mit diesem Modularisierungsmodell eine bessere Unterstützung für große Java-Projekte an. Dabei muss auch die Einbeziehung von Java SE 9 mit automatisierten Build-Werkzeugen wie Gradle betrachtet werden. Gradle Inc. ist am Jigsaw JSR beteiligt und arbeitet an einem Gradle-Modell, um ein bestmögliches Jigsaw-kompatibles Komponentenmodell für JDK 9 anzubieten, wie es bereits für Java SE 7 und Java SE 8 existiert.

Mit dem JDK 9 verschmelzen die bisherige Java ME mit der Java SE, sodass es dann nur noch die Java SE gibt. Die notwendigen Funktionsmerkmale können mithilfe von Jigsaw und seinen Werkzeuge individuell zusammengestellt und durch die passenden Images auch für kleinere Geräte maßgeschneidert erstellt werden.

Geschrieben von
Wolfgang Weigend
Wolfgang Weigend
Wolfgang Weigend arbeitet als Sen. Leitender Systemberater bei der Oracle Deutschland B.V. & Co. KG. Er beschäftigt sich mit Java-Technologie und -Architektur für unternehmensweite Anwendungsentwicklung.
Kommentare

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht.