Java 9 bringt uns das neue Modulsystem Jigsaw (englisch, u.a. für Puzzle). Wir haben jetzt Module in Java 9. Doch was heißt das konkret?
In einigen Artikeln auf diesem Blog soll Jigsaw näher erläutert werden.
- Teil 1: Modul-Deklaration und Modul-Abhängigkeiten
- Teil 2: Exportieren von Java-Packages und Interfaces aus Modulen
- Teil 3: Modulkategorien und Umgang mit Legacy-Code (Java <= 8)
Modul-Deklaration und Modul-Abhängigkeiten
Eine tiefgreifende Änderung von Java 9 ist, dass es den universalen und allgegenwärtigen Classpath nicht mehr gibt. Die Tatsache, dass jede beliebige Klasse mit public-Modifikator überall innerhalb einer JVM einsetzbar ist, gilt nicht mehr.
Stattdessen gehört nun jede Klasse zu einem Java-Modul und Zugriffe auf Klassen über Modul-Grenzen hinweg sind nicht mehr ohne weiteres möglich. Die Animation in Abbildung 1 soll diese Neuerung verdeutlichen. Der früher global gültige Classpath wird nun durch die Modulgrenzen eingeschränkt.
Definition von Modulen
Man definiert Module über die Modul-Deklaration in der Datei module-info.java, die man im Quellcode-Wurzelverzeichnis ablegt.
In der Modul-Deklaration legt man für ein Modul folgende Daten fest:
- den Modulnamen
- Java-Packages, die das Modul nach außen exportiert.
- andere Java-Module, die vom Modul benötigt werden
- Java-Interfaces, die das Modul implementiert
- Java-Implementierungen, mit denen die zuvor genannten Java-Interfaces implementiert werden.
Es folgen einige Beispiele.
Eine simple Moduldefinition
Hier sehen wir eine simple Moduldefinition. Beim Exportieren von Packages kann leider nicht mit Wildcards gearbeitet werden. Deswegen muss jedes Package einzeln exportiert werden. Darunter liegende Packages erfordern ein eigenes exports-Statement.
/** * Modul mit dem Namen * de.holisticon.servlet4demospringboot */ module de.holisticon.servlet4demospringboot { // Exportierte Packages aus diesem Modul exports de.holisticon.servlet4demospringboot; exports de.holisticon.servlet4demospringboot.util; // Benötigte Module ... requires spring.core; requires spring.beans; requires spring.context; requires javax.servlet.api; requires log4j.over.slf4j; }
Listing 1: Eine simple Moduldefinition
Transitive Abhängigkeiten
Module-Abhängigkeiten werden können transitiv weitergegeben werden, sofern sie entsprechend definiert werden. In diesem Beispiel sehen wird das Modul module-ten, welches vom Modul module-one abhängig ist.
Letzteres definiert seinerseits zwei Abhängigkeiten zu den Modulen module-two und module-three.
module-ten ist in der Lage, Funktionalität von module-one zu nutzen, da es dieses direkt per requires-Anweisung referenziert. module-ten hat keinen Zugriff auf module-two, da es dieses nicht direkt referenziert. module-one gibt lediglich die Abhängigkeit auf module-three transitiv weiter.
Folglich kann module-ten die Funktionalität von module-three nutzen, da es die Abhängigkeit darauf von module-one erbt.
/** * Modul mit dem Namen * de.holisticon.servlet4demospringboot */ module module-ten { requires module-one; } module module-one { requires module-two; requires transitive module-three; }
Listing 2: Moduldefinitionen mit transitiven Abhängigkeiten
+---------------+ | module-ten | +-+-------------+ | | requires | +-------------------------v+ | module-one | +--+---------------------+-+ | | requires | | requires transitive | | +------v-----+ +------v---------+ | module-two | | module-three | +------------+ +----------------+
Ausblick
Im nächsten Artikel wird der Aspekt der Bereitstellung der Funktionalität von Modulen behandelt.
Bildhinweis
Bild mit Puzzle-Teilen von Lilla Frerichs unter Public Domain Dedication Lizenz.