Modulare Java-Zukunft: Das Java Platform Module System erklärt

Seite 4: Automatic Modules und mehr

Inhaltsverzeichnis

Möchte ein Projekt die Vorteile des Modulsystems genießen, ohne dass alle Abhängigkeiten modularisiert sind, sind letztere dennoch zu deklarieren. Da sie im Unnamed Module landen, müsste das etwa so aussehen:

module org.codefx.foo {
// Guava 20 is not modularized;
// it ends up on the class path
requires unnamed; // or something
}

Das funktioniert allerdings nicht – das Unnamed Modul ist nunmal namenlos und lässt sich nicht referenzieren. Das ist keine technische Schwäche, sondern eine absichtliche Hürde. Sie soll verhindern, dass angenehm modularisierte Artefakte vom Chaos des Class Path abhängen können. Stattdessen wurde die Möglichkeit entwickelt, eine Brücke vom Module zum Class Path zu schlagen.

Befindet sich ein reguläres JAR auf dem Module Path, erzeugt das Modulsystem daraus ein Automatic Module. Der Name des Moduls leitet sich vom Dateinamen ab (so wird etwa aus guava-20.0.jar das Modul guava), und da sich weder Abhängigkeiten noch API bestimmen lassen, wird auch hier jedes Modul gelesen und jedes Paket exportiert. Das ähnelt dem Unnamed Module, aber es gibt zwei entscheidende Unterschiede:

  • Zu jedem JAR wird ein Automatic Module erstellt.
  • Automatic Modules haben Namen, weswegen sich Abhängigkeiten von ihnen definieren lassen.

Damit kann die vorangegangene Module Declaration folgendermaßen aussehen:

module org.codefx.foo {
// Guava 20 is still not modularized;
// this time it ends up on the module path
requires guava;
}

Auf die Weise lassen sich Projekte, die von Guava abhängen, unabhängig davon modularisieren.

Dass die Namen automatischer Module vom Dateinamen abhängen und damit nicht stabil sind, kann allerdings zu Problemen führen, wenn Artefakte das gleiche Modul mit unterschiedlichen Namen referenzieren. Das JDK-Team rät deswegen davon ab, Module mit Abhängigkeiten auf automatische Module zu publizieren (z. B. auf Maven Central). Als Konsequenz wird die Modularisierung des gesamten Ökosystems einer Bottom-Up-Strategie folgen müssen und sicherlich einige Jahre dauern.

Zum aktuellen Zeitpunkt ist es wichtig, über Kompatibilität, Migration und schrittweise Modularisierung zu reden. Da das eher negativ belegte Themen sind, verliert man schnell aus den Augen, was das Modulsystem noch zu bieten hat. Da sind insbesondere die detaillierteren Optionen zu nennen, um Abhängigkeiten (z. B. optionale) und APIs (z. B. nur für Reflection) zu definieren.

Darüber hinaus gibt es beispielsweise Services, mit denen sich Abhängigkeiten zwischen Modulen entkoppeln lassen. Ein weiteres spannendes Feature sind Layer, die dabei helfen, modularisierte Anwendungen isoliert oder hierarchisch organisiert zu starten, was insbesondere Container wie Application Server benötigen.

Mit einem in Module zerlegten JDK und klar definierten Abhängigkeiten ist es möglich, eine Laufzeitumgebung zusammenzustellen, die nur aus genau dem besteht, was die Anwendung benötigt. Das neue Tool jlink erlaubt ausgehend von einer Menge direkt verwendeter Module alle indirekt benötigten zu bestimmen und daraus eine Laufzeitumgebung zu erstellen. Damit sollen die Zeiten vorbei sein, in denen der Code für XML, SQL oder AWT/Swing/JavaFX immer auch auf einem Raspberry Pi oder in einem Docker Image vorhanden sind. Dank Compact Profiles war das zwar seit Java 8 nicht mehr nötig, aber jlink ist wesentlich flexibler.