Warum Jigsaw / JPMS projizieren?

79

Das Paketverwaltungssystem von Java schien mir immer einfach und effektiv zu sein. Es wird stark vom JDK selbst verwendet. Wir haben es verwendet, um das Konzept von Namespaces und Modulen nachzuahmen.

Was versucht Project Jigsaw (auch bekannt als Java Platform Module System ) auszufüllen?

Von der offiziellen Seite:

Das Ziel dieses Projekts ist es, ein Standardmodulsystem für die Java SE-Plattform zu entwerfen und zu implementieren und dieses System auf die Plattform selbst und auf das JDK anzuwenden.

John
quelle

Antworten:

100

Jigsaw und OSGi versuchen, dasselbe Problem zu lösen: Wie können gröberkörnige Module interagieren und gleichzeitig ihre Interna abgeschirmt werden?

In Jigsaws Fall enthalten die gröberkörnigen Module Java-Klassen, -Pakete und deren Abhängigkeiten.

Hier ist ein Beispiel: Frühling und Winterschlaf. Beide sind von einer JAR-CGLIB eines Drittanbieters abhängig, verwenden jedoch unterschiedliche, inkompatible Versionen dieser JAR. Was können Sie tun, wenn Sie sich auf das Standard-JDK verlassen? Einschließlich der Version, die Spring will, bricht der Ruhezustand und umgekehrt.

Wenn Sie jedoch ein übergeordnetes Modell wie Jigsaw haben, können Sie problemlos verschiedene Versionen einer JAR in verschiedenen Modulen verwalten. Stellen Sie sich diese als übergeordnete Pakete vor.

Wenn Sie Spring aus der GitHub-Quelle erstellen, sehen Sie es auch. Sie haben das Framework überarbeitet, sodass es aus mehreren Modulen besteht: Kern, Persistenz usw. Sie können die minimalen Modulabhängigkeiten auswählen, die Ihre Anwendung benötigt, und den Rest ignorieren. Früher war es eine einzelne Spring-JAR mit allen darin enthaltenen .class-Dateien.

Update: Fünf Jahre später - Jigsaw muss möglicherweise noch einige Probleme lösen.

Duffymo
quelle
5
Was wäre, wenn Sie immer noch genau dasselbe Modul verwenden müssten, aber zwei verschiedene Versionen davon? Sollten sie nicht einfach irgendeine Art von Unterstützung hinzufügen, damit zwei Versionen derselben Klassen nebeneinander existieren können?
Didier A.
7
Dieser Beitrag ist irreführend, da er tatsächlich in Java 9 veröffentlicht werden soll. Möglicherweise war er zum Zeitpunkt des Schreibens korrekt.
Xenoterracide
1
mreinhold.org/blog/jigsaw-complete Projekt abgeschlossen und für Java 9 freigegeben
Zasz
@ Xenoterracide, Sie können niemandem vorwerfen, dass er nicht hellsichtig ist. Der Beitrag ging Java 9 um fünf Jahre voraus. Überprüfen Sie auch jede Antwort von Jon Skeet?
Duffymo
44

AFAIK Der Plan ist, die JRE modularer zu gestalten. Dh haben kleinere Gläser, die optional sind und / oder Sie können nur die Funktionalität herunterladen / aktualisieren, die Sie benötigen.

Dies soll die Aufblähung verringern und Ihnen die Möglichkeit geben, ältere Module zu löschen, die die meisten Benutzer möglicherweise nicht verwenden.

Peter Lawrey
quelle
6
Die akzeptierte Antwort ist gültig, aber diese Antwort ist besser, weil sie die tatsächlich gewünschten Effekte erklärt. +1, verdient.
Silviu Burcea
Ich bin neugierig. Bedeutet dies auch, dass ich Google Guava als Abhängigkeit habe, aber nur die ImmutableList darin verwende. Dann kann ich nur ImmutableList-Abhängigkeiten importieren und den Rest der Guava-Klassen weglassen.
tmn
1
@ ThomasN. Wenn Sie ein importverwenden, wird diese Klasse lediglich in den Namensraum der Klasse für den Compiler eingeführt. Wenn Sie es nicht verwenden, wird es nicht im erstellten Bytecode angezeigt. Wenn Sie die Klasse tatsächlich verwenden, benötigen Sie diese Klasse und jede Klasse, die sie zur Laufzeit verwendet. Theoretisch könnten Sie eine abgespeckte Version der Guava-API erstellen, die nur das enthält, was Sie benötigen, und stattdessen diese JAR verwenden. In der Realität ist dies fehleranfällig und in den meisten Fällen nicht sehr nützlich, und Sie fügen am Ende nur die gesamte JAR hinzu, wie sie freigegeben wurde.
Peter Lawrey
43

Basierend auf Mark Reinhold ‚s Keynote auf Devoxx Belgien , Projekt Jigsaw wird zu Adresse zwei Hauptschmerzpunkte:

  1. Klassenpfad
  2. Massives monolithisches JDK

Was ist los mit Classpath?

Wir alle kennen die JAR-Hölle . Dieser Begriff beschreibt die verschiedenen Möglichkeiten, mit denen der Klassenladevorgang möglicherweise nicht funktioniert. Die bekanntesten Einschränkungen von classpath sind:

  • Es ist schwer zu sagen, ob es Konflikte gibt. Build-Tools wie Maven können basierend auf Artefaktnamen ziemlich gute Arbeit leisten. Wenn die Artefakte selbst unterschiedliche Namen, aber denselben Inhalt haben, kann es zu einem Konflikt kommen.
  • Das grundlegende Problem bei JAR-Dateien ist, dass sie keine Komponenten sind. Es sind nur ein paar Dateicontainer, die linear durchsucht werden. Mit Classpath können Sie nach Klassen suchen, unabhängig davon, in welchen Komponenten sie sich befinden, in welchen Paketen sie sich befinden oder für welche Zwecke sie vorgesehen sind.

Massives monolithisches JDK

Die große monolithische Natur von JDK verursacht mehrere Probleme:

  • Es passt nicht auf kleine Geräte. Obwohl kleine IoT-Geräte über Prozessoren verfügen, auf denen eine VM der SE-Klasse ausgeführt werden kann, verfügen sie nicht unbedingt über den Speicher, um das gesamte JDK aufzunehmen, insbesondere wenn die Anwendung nur einen kleinen Teil davon verwendet.
  • Es ist sogar ein Problem in der Cloud. In der Cloud geht es darum, die Verwendung von Hardware zu optimieren. Wenn Sie Tausende von Images mit dem gesamten JDK erhalten, Anwendungen jedoch nur einen kleinen Teil davon verwenden, wäre dies eine Verschwendung.

Module: Die gemeinsame Lösung

Um die oben genannten Probleme zu lösen, behandeln wir Module als eine grundlegende neue Art von Java-Programmkomponente. Ein Modul ist eine benannte, selbstbeschreibende Sammlung von Code und Daten. Sein Code ist als eine Reihe von Paketen organisiert, die Typen enthalten, dh Java-Klassen und -Schnittstellen. Die Daten umfassen Ressourcen und andere Arten statischer Informationen.

Um zu steuern, wie sich der Code auf Typen in anderen Modulen bezieht, gibt ein Modul an, welche anderen Module es zum Kompilieren und Ausführen benötigt. Um zu steuern, wie Code in anderen Modulen auf Typen in seinen Paketen verweist, gibt ein Modul an, welches dieser Pakete es exportiert.

Das Modulsystem lokalisiert die erforderlichen Module und stellt im Gegensatz zum Klassenpfadmechanismus sicher, dass der Code in einem Modul nur auf Typen in den Modulen verweisen kann, von denen er abhängt. Die Zugriffssteuerungsmechanismen der Java-Sprache und der Java Virtual Machine verhindern, dass Code auf Typen in Paketen zugreift, die nicht von ihren definierenden Modulen exportiert werden.

Modularität ist nicht nur zuverlässiger, sondern kann auch die Leistung verbessern. Wenn sich Code in einem Modul auf einen Typ in einem Paket bezieht, wird dieses Paket garantiert entweder in diesem Modul oder in genau einem der von diesem Modul gelesenen Module definiert. Wenn Sie nach der Definition eines bestimmten Typs suchen, müssen Sie daher nicht in mehreren Modulen oder, schlimmer noch, entlang des gesamten Klassenpfads danach suchen.

JEPs folgen

Jigsaw ist ein riesiges Projekt, das seit einigen Jahren läuft. Es gibt eine beeindruckende Anzahl von JEPs, die großartige Orte sind, um mehr Informationen über das Projekt zu erhalten. Einige dieser JEPs sind wie folgt:

  • JEP 200: Das modulare JDK : Verwenden Sie das Java Platform Module System (JPMS), um das JDK zu modularisieren
  • JEP 201: Modularer Quellcode : Reorganisieren Sie den JDK-Quellcode in Module, erweitern Sie das Build-System, um Module zu kompilieren, und erzwingen Sie Modulgrenzen beim Erstellen
  • JEP 261: Modulsystem : Implementieren Sie das Java Platform Module System gemäß JSR 376 zusammen mit den zugehörigen JDK-spezifischen Änderungen und Erweiterungen
  • JEP 220: Modulare Laufzeitimages : Restrukturieren Sie die JDK- und JRE-Laufzeitimages, um Module aufzunehmen und Leistung, Sicherheit und Wartbarkeit zu verbessern
  • JEP 260: Kapselung der meisten internen APIs : Machen Sie die meisten internen APIs des JDK standardmäßig unzugänglich, lassen Sie jedoch einige wichtige, weit verbreitete interne APIs zugänglich, bis unterstützte Ersetzungen für alle oder die meisten ihrer Funktionen vorhanden sind
  • JEP 282: jlink: Der Java Linker : Erstellen Sie ein Tool, mit dem Sie eine Reihe von Modulen und ihre Abhängigkeiten zu einem benutzerdefinierten Laufzeitabbild zusammenstellen und optimieren können, wie in JEP 220 definiert

Schlußbemerkungen

In der ersten Ausgabe des Berichts über den Status des Modulsystems beschreibt Mark Reinhold die spezifischen Ziele des Modulsystems wie folgt:

  • Zuverlässige Konfiguration , um den spröden, fehleranfälligen Klassenpfadmechanismus durch ein Mittel zu ersetzen, mit dem Programmkomponenten explizite Abhängigkeiten voneinander deklarieren können, zusammen mit
  • Starke Kapselung , damit eine Komponente deklarieren kann, welche ihrer öffentlichen Typen für andere Komponenten zugänglich sind und welche nicht.

Diese Funktionen kommen Anwendungsentwicklern, Bibliotheksentwicklern und Implementierern der Java SE-Plattform selbst direkt und indirekt zugute, da sie eine skalierbare Plattform, eine größere Plattformintegrität und eine verbesserte Leistung ermöglichen.

Ali Dehghani
quelle
3
Mark Reinhold ist der Chefarchitekt der Java Platform Group bei Oracle, und diese Antwort ist im Wesentlichen seine direkte Antwort auf genau diese Frage.
Jay
1
Um dies zu quantifizieren, kann HelloWorld 15 MB anstelle von 553 MB verwenden. youtu.be/rFhhLXcOBsk?t=31m12s
user1133275
14

Nehmen wir aus Gründen der Argumentation an, dass Java 8 (und früher) bereits eine "Form" von Modulen (Jars) und Modulsystem (Klassenpfad) hat. Es gibt jedoch bekannte Probleme mit diesen.

Indem wir die Probleme untersuchen, können wir die Motivation für Jigsaw veranschaulichen. (Im Folgenden wird davon ausgegangen, dass wir keine OSGi, JBoss-Module usw. verwenden, die mit Sicherheit Lösungen bieten.)

Problem 1: Öffentlichkeit ist zu öffentlich

Betrachten Sie die folgenden Klassen (vorausgesetzt, beide sind öffentlich):

com.acme.foo.db.api.UserDao
com.acme.foo.db.impl.UserDaoImpl

Bei Foo.com entscheiden wir möglicherweise, dass unser Team verwenden UserDaound nicht UserDaoImpldirekt verwenden soll. Es gibt jedoch keine Möglichkeit, dies im Klassenpfad durchzusetzen.

In Jigsaw enthält ein Modul eine module-info.javaDatei, mit der wir explizit angeben können, was für andere Module öffentlich ist. Das heißt, die Öffentlichkeit hat Nuancen. Zum Beispiel:

// com.acme.foo.db.api.UserDao is accessible, but
// com.acme.foo.db.impl.UserDaoImpl is not 
module com.acme.foo.db {
    exports com.acme.foo.db.api;
}

Problem 2: Reflexion ist ungezügelt

Angesichts der Klassen in # 1 könnte jemand dies in Java 8 noch tun:

Class c = Class.forName("com.acme.foo.db.impl.UserDaoImpl");
Object obj = c.getConstructor().newInstance();

Das heißt: Reflexion ist mächtig und wesentlich, aber wenn sie nicht aktiviert ist, kann sie verwendet werden, um auf unerwünschte Weise in die Interna eines Moduls zu gelangen. Mark Reinhold hat ein ziemlich alarmierendes Beispiel . (Der SO-Beitrag ist hier .)

In Jigsaw bietet eine starke Kapselung die Möglichkeit, den Zugriff auf eine Klasse einschließlich Reflexion zu verweigern. (Dies kann von den Befehlszeileneinstellungen abhängen, bis die überarbeitete technische Spezifikation für JDK 9 vorliegt.) Da Jigsaw für das JDK selbst verwendet wird, behauptet Oracle, dass das Java-Team dadurch die Plattforminternale schneller innovieren kann.

Problem 3: Der Klassenpfad löscht architektonische Beziehungen

Ein Team hat normalerweise ein mentales Modell für die Beziehungen zwischen Gläsern. Zum Beispiel foo-app.jarkann verwenden, foo-services.jarwelche Verwendungen foo-db.jar. Wir könnten behaupten, dass Klassen in foo-app.jar"die Serviceschicht" nicht umgehen und foo-db.jardirekt verwenden sollten. Es gibt jedoch keine Möglichkeit, dies über den Klassenpfad zu erzwingen. Mark Reinhold erwähnt dies hier .

Im Vergleich dazu bietet Jigsaw ein explizites, zuverlässiges Barrierefreiheitsmodell für Module.

Problem 4: monolithische Laufzeit

Die Java-Laufzeit ist monolithisch rt.jar. Auf meinem Computer sind es mehr als 60 MB mit 20.000 Klassen! In Zeiten von Mikrodiensten, IoT-Geräten usw. ist es unerwünscht, Corba, Swing, XML und andere Bibliotheken auf der Festplatte zu haben, wenn sie nicht verwendet werden.

Jigsaw unterteilt das JDK selbst in viele Module. zB java.sql enthält die bekannten SQL - Klassen. Dies hat mehrere Vorteile, aber ein neuer ist das jlinkWerkzeug. Angenommen, eine App ist vollständig modularisiert, jlinkwird ein verteilbares Laufzeit-Image generiert , das so beschnitten ist, dass es nur die angegebenen Module (und ihre Abhängigkeiten) enthält. Mit Blick auf die Zukunft sieht Oracle eine Zukunft vor, in der die JDK-Module vorab zu nativem Code kompiliert werden. Obwohl dies jlinkoptional ist und die AOT-Kompilierung experimentell ist, sind sie wichtige Hinweise darauf, wohin Oracle steuert.

Problem 5: Versionierung

Es ist bekannt, dass der Klassenpfad es uns nicht erlaubt, mehrere Versionen desselben JARs zu verwenden: zB bar-lib-1.1.jarund bar-lib-2.2.jar.

Jigsaw geht dieses Problem nicht an. Mark Reinhold gibt hier die Gründe an . Das Wesentliche ist, dass Maven, Gradle und andere Tools ein großes Ökosystem für das Abhängigkeitsmanagement darstellen und eine andere Lösung eher schädlich als nützlich ist.

Es sollte beachtet werden, dass andere Lösungen (z. B. OSGi) dieses Problem tatsächlich angehen (und andere, abgesehen von # 4).

Endeffekt

Das sind einige wichtige Punkte für Jigsaw, die durch spezifische Probleme motiviert sind.

Beachten Sie, dass das Erklären der Kontroverse zwischen Jigsaw-, OSGi-, JBoss-Modulen usw. eine separate Diskussion ist, die zu einer anderen Stack Exchange-Site gehört. Es gibt viel mehr Unterschiede zwischen den Lösungen als hier beschrieben. Darüber hinaus bestand ein ausreichender Konsens, um den Stimmzettel zur Überprüfung der öffentlichen Überprüfung für JSR 376 zu genehmigen .

Michael Ostern
quelle
3

In diesem Artikel werden die Probleme, die sowohl OSGi als auch JPMS / Jigsaw zu lösen versuchen, ausführlich erläutert:

"Java 9, OSGi und die Zukunft der Modularität" [22. September 2016]

Es wird auch ausführlich auf die Ansätze von OSGi und JPMS / Jigsaw eingegangen. Derzeit scheinen die Autoren im Vergleich zu gereiftem (16 Jahre alt) OSGi fast keine praktischen Vorteile für JPMS / Jigsaw aufgeführt zu haben.

uvsmtid
quelle