Database
 sql >> Datenbank >  >> RDS >> Database

Erkundung der Modul-APIs in Java 9

Java 9 hat die API in eine Sammlung von Modulen integriert. Daher ist Modularität das zentrale Thema; Dies betraf das Programmdesign von der obersten Ebene. Programme können von Anfang an modular aufgebaut werden. Es ist keine Überraschung, dass es APIs geben wird, die sich speziell mit dem als Modul bezeichneten Programmierelement befassen . Die APIs bieten eine Möglichkeit, programmgesteuert auf Module zuzugreifen. Diese APIs sind sehr praktisch, um bestimmte Informationen über die Module zu erhalten oder sie zu lesen oder zu manipulieren. Dieser Artikel untersucht die Modul-APIs-Klassen und einige der Methoden, mit Beispielen, um Ihnen eine Vorstellung von ihrer Gesamtfunktionalität zu geben.

Ein Überblick

Java 9 bietet eine Reihe von Klassen und Schnittstellen für den programmatischen Umgang mit Modulen. Diese APIs sind besonders nützlich für:

  • Lesen, Laden und Suchen von Modulen
  • Lesen und Manipulieren von Moduldeskriptoren

Die Liste der APIs ist hauptsächlich in Paketen enthalten:java.lang und java.lang.module . Obwohl das java.lang.module Paket besteht aus den meisten Klassen und Schnittstellen, um mit Moduldeskriptoren umzugehen, der java.lang Paket enthält Klassen Modul , Modulebene , und eine Ausnahme, LayerInstantiationException . Darunter das Modul Die Klasse ist von grundlegender Bedeutung, da eine Instanz dieser Klasse alle Methoden bereitstellt, die mit dem Lesen, Laden und Suchen von Modulen verbunden sind. Die wichtigste Klasse im java.lang.module Paket ist der ModuleDescriptor . Diese Klasse stellt die notwendigen Methoden bereit, um mit Moduldeskriptoren umzugehen.

Module-API

Gemäß der Java-API-Dokumentation repräsentiert die Modulklasse sowohl benannte als auch unbenannte Laufzeitmodule. Benannte Module haben einen Namen und werden von der Java Virtual Machine konstruiert, wenn ein Graph von Modulen für die Java Virtual Machine definiert wird, um eine Modulschicht zu erzeugen. Ein unbenanntes Modul hat keinen Namen. Für jeden ClassLoader gibt es ein unbenanntes Modul , erhalten durch Aufrufen seines getUnnamedModule Methode. Alle Typen, die sich nicht in einem benannten Modul befinden, sind Mitglieder des unbenannten Moduls ihres definierenden Klassenladers.

Es ist einfach herauszufinden, zu welchem ​​Modul einer Klasse es gehört. Wenn wir zum Beispiel das Modul einer Klasse herausfinden wollen, sagen wir ArrayList , aus der Sammlungs-API oder beispielsweise Anwendung von JavaFX können wir dies folgendermaßen tun.

Class<ArrayList> c= ArrayList.class;
Module mod=c.getModule();
System.out.println(mod.getName());

Oder in einer einzigen Anweisung wie folgt:

System.out.println(Application.class
   .getModule().getName());

Dies gibt den Modulnamen der Klasse aus, z. B. java.base , für Arrayliste und javafx.graphics für Bewerbung . Da ein Modul entweder benannt oder unbenannt sein kann, können wir dies herausfinden, indem wir isNamed() aufrufen Methode. Diese Methode gibt true zurück ob das Modul benannt ist oder false wenn es sich um ein unbenanntes Modul handelt. Hier ist ein Beispiel für unbenannte Module.

package org.mano.java9.examples;
public class Main {
   public static void main(String[] args) {
      Class<Main> c= Main.class;
      Module mod=c.getModule();
      System.out.println(mod);
      System.out.println(mod.getName());
      System.out.println(mod.getName()+" is "
         +(mod.isNamed()?
         "Named Module":"Unnamed Module"));
      System.out.println(mod.getDescriptor());
   }
}

Ausgabe:

unnamed module @4c75cab9
null
null is Unnamed Module
null

Und für benannte Module können wir wie folgt schreiben:

package org.mano.java9.examples;
import java.util.ArrayList;
public class Main {
   public static void main(String[] args) {
      Class<ArrayList> c= ArrayList.class;
      Module mod=c.getModule();<
      System.out.println(mod);
      System.out.println(mod.getName());
      System.out.println(mod.getName()+" is "
         +(mod.isNamed()?
         "Named Module":"Unnamed Module"));
      System.out.println(mod.getDescriptor());
   }
}

Ausgabe:

module java.base
java.base
java.base is Named Module
module { name: [email protected], uses:
   [java.nio.file.spi.FileTypeDetector, ...}

Eine Modulebene enthält nur benannte Module. Wir können getLayer aufrufen -Methode, um die Informationen über die im Modul enthaltene Ebene abzurufen. Wenn es null zurückgibt, bedeutet dies, dass sich das Modul nicht in einer Ebene befindet oder dass es sich um ein unbenanntes Modul handelt. Wenn wir eine Liste der in einem Modul verfügbaren Pakete erhalten möchten, können wir getPackages aufrufen Methode. Der getClassLoader -Methode gibt den Klassenlader des Moduls zurück. Hier ist ein Beispiel zur Veranschaulichung der oben beschriebenen Methoden.

package org.app.module1;
import javafx.application.Application;
import java.util.Set;
public class Main {
   public static void main(String[] args) {
      Class<Application> c = Application.class;
      Module mod = c.getModule();
      System.out.println("Name :" 
         + mod.getName());
      System.out.println(mod.getName() + " is " 
         + (mod.isNamed() ? "Named Module" :
         "Unnamed Module"));
      System.out.println("Layer :" + mod.getLayer());
      System.out.println("ClassLoader :"
         + mod.getClassLoader());
      System.out.println("List of
         Packagesn.....................");
      Set<String> set = mod.getPackages();
      int i=1;
      for (String s : set) {
         System.out.println(i+++") "+s);
      }
   }
}

Ausgabe:

Name :javafx.graphics
javafx.graphics is Named Module
Layer :jdk.compiler, java.compiler, jdk.management.jfr,
   jdk.scripting.nashorn, ...
ClassLoader :jdk.internal.loader.ClassLoaders
   [email protected]
....................
List of Packages
.....................
1) com.sun.javafx.stage
2) com.sun.scenario.effect.impl.prism.ps
3) javafx.print
...
107) com.sun.prism.j2d
108) javafx.scene.image

Modulbeschreibung

Laut Java 9 API Documentation „beschreibt ein Moduldeskriptor ein benanntes Modul und definiert Methoden, um jede seiner Komponenten zu erhalten.“ Der Moduldeskriptor für ein benanntes Modul in der Java Virtual Machine wird durch Aufrufen des Moduls abgerufen 's getDescriptor Methode. Moduldeskriptoren können auch mit dem ModuleDescriptor.Builder erstellt werden Klasse oder durch Lesen der binären Form einer Moduldeklaration (module-info.class ) mit lesen Methoden, die in dieser Klasse definiert sind.

Daher typischerweise der ModuleDescriptor Die Instanz stellt die Moduldefinition dar, die in der binären Form der Moduldeskriptordatei mit dem Namen module-info.class gefunden wird . Neben dem Lesen und Manipulieren der Moduldefinition können wir den ModuleDescriptor.Builder verwenden Klasse, um das Modul zur Laufzeit zu beschreiben.

Ein Moduldeskriptor beschreibt drei Arten von Modulen, wie normale, offene und automatische Module.

Ein normales und ein offenes Modul beschreiben explizit die Dienste, die sie bereitstellen oder verwenden, Abhängigkeiten, exportierte Pakete und andere Komponenten. Der Hauptunterschied zwischen einem normalen Modul und einem offenen Modul besteht darin, dass Normale Module bestimmte Pakete öffnen können. Der Moduldeskriptor für ein offenes Modul deklariert keine offenen Pakete (seine opens -Methode gibt eine leere Menge zurück), aber wenn sie in der Java Virtual Machine instanziiert wird, wird sie so behandelt, als ob alle Pakete geöffnet wären.

Das automatische Modul deklariert jedoch keine exportierten, geöffneten Pakete oder Abhängigkeiten außer der impliziten Deklaration der java.base Modul. Wenn ein automatisches Modul in der Java Virtual Machine instanziiert wird, liest es jedes unbenannte Modul und wird behandelt, als ob alle Pakete exportiert und geöffnet wären.

Der getDescriptor Methode des Moduls Klasse gibt eine Instanz des ModuleDescriptor zurück Klasse. Der Moduldeskriptor class enthält statisch verschachtelte Klassen, deren Instanz die Direktive in der Moduldeklarationsdatei darstellt. Die Klasse enthält jedoch keine uses -Anweisung, die normalerweise durch eine Dienstinstanz String dargestellt werden kann . Hier sind die anderen vier:

  • ModuleDescriptor.Requires
  • ModuleDescriptor.Opens
  • ModuleDescriptor.Bereitstellt
  • ModuleDescriptor.Exports

Ein kurzes Beispiel

package org.mano.java9.examples;
import javax.sql.RowSet;
import java.lang.module.ModuleDescriptor;
import java.util.List;
public class Main {
   public static void main(String[] args) {
      System.out.println("Module Name: "
         + List.class.getModule().getName());
      show(List.class.getModule().getDescriptor());
      System.out.println("Module Name: "
         + RowSet.class.getModule().getName());
      show(RowSet.class.getModule().getDescriptor());
   }
   public static void show(ModuleDescriptor d) {
      System.out.println("Module
         Descriptionn-------------------------");
      System.out.println("Requires: " + d.requires());
      System.out.println("Exports: " + d.exports());
      System.out.println("Uses: " + d.uses());
      System.out.println("Provides: " + d.provides());
      System.out.println("Packages: " + d.packages());
   }
}

Ausgabe:

Module Name: java.base
Module Description
-------------------------
Requires: []
Exports: [jdk.internal.org.objectweb.asm.signature to
   [jdk.scripting.nashorn], ...]
Uses: [java.util.spi.LocaleNameProvider,
   java.nio.file.spi.FileSystemProvider, ...]
Provides: [java.nio.file.spi.FileSystemProvider with
   [jdk.internal.jrtfs.JrtFileSystemProvider]]
Packages: [java.nio.file, jdk.internal.org.objectweb.asm
   .tree.analysis, com.sun.security.ntlm, ...]
Module Name: java.sql
Module Description
-------------------------
Requires: [mandated java.base, transitive java.logging,
   transitive java.xml]
Exports: [java.sql, javax.transaction.xa, javax.sql]
Uses: [java.sql.Driver]
Provides: []
Packages: [javax.sql, javax.transaction.xa, java.sql]

Die Moduldeskriptor-Binärdatei namens module-info.class , kann auf folgende Weise direkt gelesen werden, um eine Instanz des ModuleDescriptor zu erstellen Klasse:

try {
   ModuleDescriptor descriptor = ModuleDescriptor
      .read(new FileInputStream("module-info.class"));
} catch (IOException ex) { }

Es gibt vier Versionen des überladenen statischen Lesens Methode, die im ModuleDescriptor definiert ist Klasse. Sie werden verwendet, um die binäre Form der Modulbeschreibung aus einem Eingabestrom oder einem Bytepuffer zu lesen. Hier ist der Auszug aus der Java 9 API-Dokumentation.

  • read(InputStream in) :Liest die binäre Form einer Moduldeklaration aus einem Eingabestrom als Moduldeskriptor.
  • read(InputStream in, Supplier > packageFinder) :Liest die binäre Form einer Moduldeklaration aus einem Eingabestrom als Moduldeskriptor.
  • read(ByteBuffer bb) :Liest die binäre Form einer Moduldeklaration aus einem Bytepuffer als Moduldeskriptor.
  • read(ByteBuffer bb, Lieferant > packageFinder) :Liest die binäre Form einer Moduldeklaration aus einem Bytepuffer als Moduldeskriptor.

Die eingestellten Pakete von packageFinder schließt alle Pakete ein, die das Modul exportiert, öffnet, bereitgestellte Dienste und das Paket der Hauptklasse, die nicht durch den Deskriptor codiert sind, der im Eingabestrom oder Bytepuffer bereitgestellt wird.

Schlussfolgerung

Neben dem Lesen grundlegender Informationen über das Modul bietet das Modul -Klasse bietet einige wichtige Methoden zum Abfragen des Modulstatus – ob es gelesen, geöffnet, exportiert usw. ist. Die API stellt auch Methoden wie addOpens bereit , addExport , addUses und addReads zum programmgesteuerten Hinzufügen von open- und export-uses und read-Anweisungen zum Moduldeskriptor. Kurz gesagt, die Modul-API bietet viele andere Methoden, um programmgesteuert speziell mit Modulen umzugehen. Hier haben wir nur an der Oberfläche gekratzt, um einen ersten Eindruck davon zu vermitteln, worum es geht.