Sequenz
Dieser Artikel untersucht hauptsächlich einige Vorsichtsmaßnahmen für die Migration zu Java9.
Migrationstypen
Einige Dinge zu beachten
Unleserliche Klassen
Zum Beispiel wird sun.security.x509 in das java.base -Modul in Java9 eingeteilt, das Modul exportiert das Paket jedoch nicht.
Sie können die Exporteinstellungen durch Hinzufügen von --add-exports java.base/sun.security.x509 = All-nicht-Named beim Laufen ändern
Interne Klasse
Zum Beispiel wollte Sun.misc.unsafe ursprünglich das Oracle JDK -Team verwenden. Da diese Klassen jedoch zu weit verbreitet sind, hat Java9 Kompromisse eingereicht, um eine Rückwärtskompatibilität zu sein, diese Klassen jedoch nur in das JDK.unsupported -Modul einzuordnen und ihre Lesbarkeit nicht einschränken.
➜ ~ java -d jdk.unsupporteedjdk.unsupported@9exports com.sun.nio.Fileexports sun.miscexports sun.reflectrectrectlectection Java.Base MandatedOpens Sun.miscopens sun.reflect
Gelöschte Klasse
Java9 gelöscht Sun.misc.base64Encoder, in diesem Fall können Sie stattdessen nur andere APIs verwenden, wie z. B. java.util.base64
ClassPath vs Modul-Pfad
Java9 führte ein Modulsystem ein, und sein eigener JDK wurde ebenfalls modularisiert, und Modulpfad wurde eingeführt, um den Klassenpfad zu blockieren. Das heißt, Modulpfad wird in Java9 bevorzugt. Schließlich ist JDK selbst modular. Wenn die Anwendung selbst nicht modular ist, wird Java9 implizit durch unbenannte Module und automatische Modulemechanismen modularisiert. Natürlich kann ClassPath weiterhin bei Java9 verwendet werden, wie z. B. die Verwendung von Modulpfaden.
Ein Glas ohne Modularität wird als unbenannte Module im Klassenpfad eingestuft. Im Modul-Pfad wird es automatisch als automatische Module erstellt (ein automatisches Modul erklärt, dass Transitive von allen benannten und unbenannten Modulen abhängt und dann ein eigenes Paket exportiert).
Ein Paketname kann in mehreren Modulen nicht angezeigt werden (geteilte Pakete)
Da Exporte in anderen Modulen in Modulen angegeben werden können, verursacht dies, wenn mehrere Module denselben Paketnamen exportieren, Verwirrung. Insbesondere wenn es andere Klassenbibliotheken gibt, in denen diese beiden Module gleichzeitig erforderlich sind, wissen Sie nicht, auf welches Modul verwiesen werden soll.
Transitive Abhängigkeiten
Wenn die Schnittstellenparameter oder der Rückgabetyp eines Moduls die Klassen anderer Module verwenden, wird empfohlen, transitive Module zu erfordern, von denen er abhängt.
Achten Sie auf kreisförmige Abhängigkeiten
Überlegen Sie, ob es beim Entwerfen von Modulen so weit wie möglich kreisförmige Abhängigkeiten geben wird. Wenn ja, müssen Sie sie neu gestalten.
Verwenden Sie Services, um optionale Abhängigkeiten zu implementieren
Die Dienste eignen sich besonders für die Entkopplung der Abhängigkeiten von Anrufern und Implementierungsklassen. Wenn die Schnittstelle über mehrere Implementierungsklassen verfügt, muss der Anrufer nicht alle Implementierungsklassen benötigen, sondern nur die erforderliche Schnittstelle benötigen und den Dienste -Typ zum Laden von Instanzen der Implementierungsklasse verwenden. Die Entkopplung erfolgt durch dynamisches Hinzufügen von Implementierungsmodulen im Modul-Pfad.
Modulversionsverwaltung
Modul-info.java unterstützt nicht die Deklaration von Versionsnummern, aber beim Erstellen von JAR-Paketen können Sie sie durch-Modul-Version einstellen. Wenn das Modulsystem jedoch nach Modulen sucht, wird der Modulname weiterhin gesucht (wenn im Modul-Pfad mehrere doppelte Module vorhanden sind, kann das Modulsystem das erste gefundene verwenden und das nachfolgende Modul automatisch mit demselben Namen ignorieren). Das Problem der Versionsabhängigkeit liegt nicht im Rahmen der Lösung des Modulsystems und bleibt den Abhängigkeitsmanagement -Tools wie Maven zur Verwaltung überlassen.
Modulressourcenzugriff
Nach der Modularisierung ist auch die Ressourcendatei geschützt und das Modul kann nur auf die Ressourcendatei des Moduls selbst zugreifen. Wenn der Zugang zum Quermodul erforderlich ist, müssen Sie auch den Modulelayer verwenden, um das Zielmodul zu finden, und dann das Zielmodul aufrufen, um die Ressourcendatei des Moduls zu laden.
Verwendung von Reflexion
Dies beinhaltet das tiefe Reflexionsproblem. Die sogenannte tiefe Reflexion besteht darin, das nicht öffentliche Element einer Klasse durch Reflexion zu bezeichnen. Die Exporte von Modul-info.java erklären, dass das Paket nur die Klasse ermöglicht, zu der das Paket direkt zugänglich ist, um den Zugriff auf sein öffentliches Element zu ermöglichen, und keine Reflexionsaufrufe zu nicht öffentlichen Elementen zulässt.
Reflection benötigt spezielle Erklärungen, die im Modulsystem zulässig sind (unter Verwendung von Open -Erklärungen, um eine tiefe Reflexion zu ermöglichen), was zu vielen Klassenbibliotheken führt, die Reflexion verwenden, z. B. Spring, für die zusätzliche Konfiguration auf Java9 migriert werden muss. Es gibt zwei Lösungen: Eine soll den Paketnamen für Module öffnen, die reflektiert werden, wie z. B. Frühling.bohnen usw.; Das andere ist, das gesamte Modul direkt zu öffnen.
Die Standardeinstellung-iillegal-access = Erlaubnis, und diese Einstellung gilt nur für Pakete vor Java9, die nicht in Java9 zugreifen dürfen und nicht für neue Pakete anwendbar sind, die nicht in Java9 zugreifen dürfen. (Es wird empfohlen, bei der Migration auf ein modulares System zu leugnen.)
Im Modulsystem sind die Paketnamen jedoch unterschiedlich und es gibt keine Vererbungsbeziehung. Zum Beispiel sind com.service.func1 und com.service.func2 verschiedene Pakete. Sie können Com.service nicht einfach öffnen, aber Sie müssen sie separat angeben, was zu mehr Paketen führt, die das Öffnen erfordern. Daher kann das Öffnen des gesamten Moduls einfacher zu bedienen sein, aber es ist auch ein relativ grober Ansatz.
Die obige Methode besteht darin, Änderungen in der ursprünglichen Modul-info.java vorzunehmen. Eine andere Methode besteht darin, die ursprüngliche Beziehung durch den angegebenen Befehl bei der Ausführung von Java oder Javac zu ändern. Zum Beispiel
Java ...-Add-Opens Quell-Modul/Quellpackage = Target-Module
Wenn Sie in unbenannte Module exportieren müssen, ist das Target-Modul ganz nicht genannt
Wenn es sich um ein neues System handelt, wird es natürlich nicht empfohlen, Reflexion zu verwenden. Methodenhände und Varhandles können verwendet werden.
FAQs und Maßnahmen
ClassNotFoundException/noclassDeffoundError
Beispielsweise wurde JAXB javax.xml.bind.jaxBexception in das Modul java.xml.bind eingeteilt und wird nach Java -Benennung hinzugefügt.
--add-Modules java.xml.bind
Wenn Sie Probleme sparen möchten, fügen Sie $ java_home und alle Bibliothek von Drittanbietern in Modul-Pfad hinzu und tun Sie dann dies
-ADD-Modules All-Module-Pfad
illegaler reflektierender Zugriff von XXX auf Methode java.lang.classloader.defineclass
Die Reflexion verursacht, da das alte System kein Modul-Info hat, der Java-Benennung Parameter hinzufügen und es ändern.
--Add-Opens java.base/java.lang = all-nicht namens
Bestimmen Sie das Abhängigkeitsmodul
Analyse über IDE oder JDEPS
JDEPS -CLASS -PATH 'Klassen/lib/*' -Recursive -Summary App.jar
JDEPS ist nur eine statische Codeanalyse. Wenn es eine Klasse gibt, die Reflexion verwendet, können Sie sie nicht analysieren. Sie müssen es manuell benötigen. Wenn die Abhängigkeit optional ist, können Sie statisch benötigen.
Lesbarkeitsprobleme für Modul -Unit -Tests
Wenn ein Modul für Unit-Tests verwendet wird, kann dem Unit-Testmodul die Lesbarkeits- und Reflexionsfunktionen des Zielmoduls bis zur Laufzeit über-ADD-Exports oder -Add-Opens erteilt werden. Darüber hinaus kann der Paketname der Unit -Testklasse aufgrund von Split -Paket -Problemen nicht mit dem Zielmodulpaketnamen dupliziert werden. Es stellt sich heraus, dass der Test des Maven -Projekts
Zusammenfassung
Sie können in zwei Schritten zu Java9 umziehen. Erstens sind Sie nicht zuerst modular, Sie laufen nur zuerst auf JDK9. Dann bist du modular.