Java-Remote-Methodenaufruf
RMI ( Java Remote Method Invocation ) ist ein Mechanismus, der von Java angeboten wird, um eine Methode aus der Ferne aufzurufen . Es ist Teil der Standard-Java-Laufzeitumgebung und bietet einen einfachen Mechanismus für die Serverkommunikation in verteilten reinen Java-Anwendungen. Wenn eine Kommunikation zwischen anderen Technologien erforderlich ist, sollte anstelle von RMI CORBA oder SOAP verwendet werden.
RMI zeichnet sich durch seine Benutzerfreundlichkeit bei der Programmierung aus, da es speziell für Java entwickelt wurde; bietet Objektübergabe per Referenz (von SOAP nicht erlaubt), verteilte Garbage Collection (Distributed Garbage Collector) und willkürliche Typübergabe (Funktionalität, die nicht von CORBA bereitgestellt wird).
Über RMI kann ein Java-Programm ein Objekt exportieren , wodurch das Objekt über das Netzwerk zugänglich wird und das Programm auf Anfragen an einem TCP-Port wartet . Danach kann ein Client die vom Objekt bereitgestellten Methoden verbinden und aufrufen.
Der Aufruf besteht aus den folgenden Schritten:
- Parameter-Marshalling (unter Verwendung der Serialisierungsfunktionalität von Java ).
- Aufruf der Methode (des Clients auf dem Server). Der Anrufer wartet auf eine Antwort.
- Nach Abschluss der Ausführung serialisiert der Server den Rückgabewert (falls vorhanden) und sendet ihn an den Client.
- Der Client-Code empfängt die Antwort und fährt fort, als ob der Aufruf lokal gewesen wäre.
Kontext
Seit JDK Version 1.1 hat Java seinen eigenen ORB : RMI (Remote Method Invocation). Obwohl RMI ein ORB im allgemeinen Sinne ist, ist es kein CORBA-konformes Modell. RMI ist Java-nativ, dh es ist eine Erweiterung der Kernsprache. RMI stützt sich vollständig auf den Kern der Java-Objektserialisierung sowie auf die Implementierung von Portabilität und Mechanismen zum Laden und Entladen von Objekten auf anderen Systemen usw.
Der Einsatz von RMI ist für jeden Java-Programmierer ganz selbstverständlich, da er keine neue Technologie erlernen muss, die völlig anders ist als die, mit der er entwickeln wird. RMI weist jedoch einige Einschränkungen aufgrund seiner engen Integration mit Java auf, wobei die wichtigste darin besteht, dass diese Technologie keine Interaktion mit Anwendungen zulässt, die in einer anderen Sprache geschrieben sind.
RMI ist als Erweiterung von Java eine Programmiertechnologie, die entwickelt wurde, um Probleme durch Schreiben und Organisieren von ausführbarem Code zu lösen. Damit bildet RMI zusammen mit C, C++, Smalltalk etc. einen besonderen Punkt im Bereich der Programmiertechnologien.
Der Hauptunterschied zwischen der Verwendung von RPC und RMI besteht darin, dass RMI ein Mechanismus für den Remote-Prozeduraufruf ist, der auf der Programmiersprache Java basiert, die die Interaktion zwischen Objekten unterstützt, während RPC diese Funktion nicht unterstützt.
Architektur
Die RMI-Architektur kann als Vier-Ebenen-Modell betrachtet werden.
Erste Schicht
Die erste Schicht ist die Anwendungsschicht und entspricht der tatsächlichen Implementierung der Client- und Serveranwendungen. Hier finden allgemeine Aufrufe für den Zugriff auf und den Export von Remote-Objekten statt. Jede Anwendung, die möchte, dass ihre Methoden für den Zugriff durch entfernte Clients verfügbar sind, muss diese Methoden in einer Schnittstelle deklarieren , die java.rmi.Remote erweitert. Eine solche Schnittstelle wird im Wesentlichen verwendet, um ein Objekt als fernzugänglich zu "markieren". Nachdem die Methoden implementiert wurden, muss das Objekt exportiert werden. Dies kann implizit erfolgen, wenn das Objekt die UnicastRemoteObject-Klasse (Paket java.rmi.server) erweitert, oder es kann explizit durch Aufrufen der Methode exportObject() desselben Pakets erfolgen.
Zweite Schicht
Schicht 2 ist die Proxy-Schicht oder Stub-Skelett-Schicht. Diese Schicht interagiert direkt mit der Anwendungsschicht. Alle Aufrufe von entfernten Objekten und Aktionen zusammen mit ihren Parametern und Rückgabeobjekten finden in dieser Schicht statt.
Dritte Schicht
Schicht 3 ist die Remote-Referenzschicht und für die Handhabung des semantischen Teils von Remote-Aufrufen verantwortlich. Es ist auch für die Verwaltung der Objektreplikation und die Durchführung implementierungsspezifischer Aufgaben mit entfernten Objekten verantwortlich, wie z. B. das Einrichten semantischer Persistenz und geeigneter Strategien zur Wiederherstellung nach Verbindungsabbrüchen. In dieser Schicht wird eine stromorientierte Verbindung von der Transportschicht erwartet.
Vierte Schicht
Schicht 4 ist die Transportschicht. Es ist dafür verantwortlich, die notwendigen Verbindungen herzustellen und den Datentransport von einer Maschine zur anderen zu verwalten. Das zugrunde liegende Transportprotokoll für RMI ist das Java Remote Method Protocol (JRMP), das nur von Java-Programmen "verstanden" wird.
Elemente
Jede RMI-Anwendung gliedert sich normalerweise in 2 Teile:
- Ein Server, der einige Remote-Objekte erstellt, erstellt Verweise, um sie zugänglich zu machen, und wartet darauf, dass der Client sie aufruft.
- Ein Client, der einen Verweis auf entfernte Objekte auf dem Server erhält und diese aufruft.
Beispiel
Ein RMI-Server besteht aus der Definition eines Remote-Objekts, das von Clients verwendet wird. Um ein Remote-Objekt zu erstellen, wird eine Schnittstelle definiert , und das Remote-Objekt ist eine Klasse, die diese Schnittstelle implementiert. Sehen wir uns an, wie Sie in 3 Schritten einen Beispielserver erstellen:
- Definieren Sie die Remote-Schnittstelle. Wenn eine Remote-Schnittstelle erstellt wird:
- Die Schnittstelle muss öffentlich sein.
- Es muss von der java.rmi.Remote-Schnittstelle erben, um anzugeben, dass es von jeder Java Virtual Machine aufgerufen werden kann.
- Jede entfernte Methode muss zusätzlich zu allen Ausnahmen, die sie verarbeiten kann, die java.rmi.RemoteException-Ausnahme in ihrer throws-Klausel auslösen.
öffentliche Schnittstelle MyRemoteInterface erweitert java . rmi . Remote
{
public void myMethod1 () wirft java . rmi . RemoteException ;
public int myMethod2 () wirft java . rmi . RemoteException ;
}
- Implementieren Sie die Remote-Schnittstelle
Die öffentliche Klasse MyRemoteClass
erweitert java . rmi . Server . UnicastRemoteObject
implementiert MyRemoteInterface
{
public MyRemoteClass () löst Java aus . rmi . RemoteException
{
super (); //Aufruf des Konstruktors der Basisklasse (UnicastRemoteObject)
// Konstruktorcode
}
public void myMethod1 () wirft java . rmi . RemoteException
{
// Hier fügen wir den gewünschten Code ein
System . aus . println ( "Ich bin in myMethod1()" );
}
public int myMethod2 () wirft java . rmi . RemoteException
{
Rückgabe 5 ; // Hier setzen wir den gewünschten Code
}
public void otherMethod ()
{
// Wenn wir eine andere Methode definieren, könnte sie nicht
// aus der Ferne aufgerufen werden, da sie nicht von der Remote-Schnittstelle kommt
}
public static void main ( String [] args )
{
try
{
MyRemoteInterface mir = new MyRemoteClass ();
Java . rmi . Benennung . rebind ( "rmi://" + java .net . InetAddress . getLocalHost ( ) . getHostAddress ( ) + ":" + args [ 0 ] + "/TestRMI" , mir ); } catch ( Ausnahme e ) { e . printStackTrace (); } } }
- Wie Sie sehen können, implementiert die MyRemoteClass-Klasse die MyRemoteInterface-Schnittstelle, die wir zuvor definiert haben. Außerdem erbt es von UnicastRemoteObject, einer Java-Klasse, die wir als Oberklasse verwenden können, um entfernte Objekte zu implementieren.
- Dann definieren wir innerhalb der Klasse einen Konstruktor (der die RemoteException-Ausnahme auslöst, weil sie auch von der Superklasse UnicastRemoteObject ausgelöst wird) und die Methoden der Schnittstelle(n), die er implementiert.
- Schließlich definieren wir in der main-Methode den Code, um das Remote-Objekt zu erstellen, das wir freigeben möchten, und machen das Remote-Objekt für Clients sichtbar, indem wir die Naming-Klasse und ihre rebind(...)-Methode verwenden.
Hinweis: Der Einfachheit halber haben wir die Methode main() in dieselbe Klasse eingefügt. Es könnte eine separate Klasse definiert werden, die für die Registrierung des entfernten Objekts verantwortlich ist.
- Kompilieren Sie den Server und führen Sie ihn aus
Wir haben den Server bereits definiert. Jetzt müssen wir Ihre Klassen mit den folgenden Schritten kompilieren:
- Wir kompilieren die Remote-Schnittstelle. Außerdem gruppieren wir es in einer JAR-Datei, damit es sowohl auf dem Client als auch auf dem Server vorhanden ist:
javac MyRemoteInterface.java jar cvf objRemotes.jar MyRemoteInterface.class
- Als nächstes kompilieren wir die Klassen, die die Schnittstellen implementieren. Und für jeden von ihnen generieren wir die Stub- und Skeleton-Dateien, um die Referenz auf das Remote-Objekt beizubehalten, indem wir den Befehl rmic verwenden:
set CLASSPATH=%CLASSPATH%;.\Remoteobj.jar;. javac MyRemoteClass.java rmic -d . MeineRemoteClass
Wir können in unserem Arbeitsverzeichnis sehen, dass zwei .class-Dateien automatisch generiert wurden (MiClaseRemota_Skel.class und MiClaseRemota_Stub.class), die der Stub-Skeleton-Schicht der RMI-Architektur entsprechen.
- Um den Server auszuführen, gehen wir folgendermaßen vor:
- Die RMI-Protokollierung wird gestartet, um die Protokollierung und Suche nach entfernten Objekten zu ermöglichen. Die Registrierung ist für die Verwaltung eines Satzes von gemeinsam zu nutzenden Remote-Objekten und für die Suche nach ihnen zuständig, wenn dies von Clients angefordert wird. Es wird mit der mit Java vertriebenen Anwendung rmiregistry ausgeführt, an die wir optional den Port für die Verbindung übergeben können (standardmäßig 1099).
Im Fall von Windows muss es ausgeführt werden:
Starten Sie die Registrierung 1234
Und im Fall von Linux:
Registrierung &
- Schließlich wird der Server gestartet:
java -Djava.rmi.server.hostname=127.0.0.1 MyRemoteClass 1234
- Erstellen Sie einen RMI-Client
Wir werden jetzt einen Client definieren, der auf die von uns erstellten Remote-Objekte zugreift. Dazu befolgen wir die folgenden Schritte:
- Definieren Sie die Klasse, um die erforderlichen Remote-Objekte abzurufen
Die folgende Klasse erhält ein Objekt vom Typ MyRemoteInterface, implementiert auf unserem Server:
öffentliche Klasse MyRMIClient
{
private MyRMIClient (){};
public static void main ( String [ ] args )
{
try
{
MyRemoteInterface mir = ( MyRemoteInterface ) java . rmi . Benennung . lookup ( "rmi://" +
args [ 0 ] + ":" + args [ 1 ] + "/RMITest" );
// myMethod1() so oft drucken, wie myMethod2() zurückgibt
für ( int i = 1 ; i <= myr . myMethod2 (); i ++ )
myr . meineMethode1 ();
}
catch ( Ausnahme e )
{
e . printStackTrace ();
}
}
}
Wie Sie sehen können, besteht es einfach darin, in der RMI-Registrierung des Remote-Rechners nach dem Remote-Objekt zu suchen. Dazu verwenden wir die Naming-Klasse und ihre lookup(...)-Methode.
- Kompilieren Sie den Client und führen Sie ihn aus
Nachdem wir den Client bereits definiert haben, kompilieren wir ihn wie folgt:
set CLASSPATH=%CLASSPATH%;.\Remoteobj.jar;. javac MyRMIClient.java
Dann, um den Client auszuführen, machen wir:
Java MyClientRMI 127.0.0.1 1234
Auf die Stub-Datei der entfernten Klasse muss zugegriffen werden können. Dazu kopieren wir es entweder auf den Client und fügen es in seinen CLASSPATH ein oder entfernen es aus dem CLASSPATH des Servers und fügen seinen Pfad in die java.rmi.codebase des Servers ein (falls nicht aus dem CLASSPATH des Servers entfernt, wird die Option java. rmi.codebase, und der Client kann nicht auf den Stub zugreifen.) Wenn wir uns das Fenster ansehen, in dem der RMI-Server läuft, sehen wir, wie das Remote-Objekt gefunden und seine Methoden ausgeführt wurden:
Siehe auch
Externe Links
- Einfaches RMI-Beispiel
- Java RMI Tutorial Tutorial von Sun Microsystems (auf Englisch)
- Trail: RMI Java RMI Offizielle Dokumentation
- Ein Überblick über RMI-Anwendungen Offizielle Einführung in Java RMI-Anwendungen