Autor
Milan Vucic
Programming Tutor at Codementor.io

Java RMI

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute beschäftigen wir uns mit einem recht interessanten Thema: Java RMI. Dies steht für Remote Method Invocation. Mithilfe von RMI können Sie zwei Programmen ermöglichen, miteinander zu kommunizieren, auch wenn sie sich auf unterschiedlichen Computern befinden. Klingt das cool? :) Und es ist gar nicht so schwer! In der heutigen Lektion analysieren wir die Elemente der RMI-Interaktion und finden heraus, wie man sie konfiguriert. Das erste, was wir brauchen, ist ein Client und ein Server. Wir müssen nicht wirklich tief in die Computerterminologie eintauchen. Wenn es um RMI geht, sind das nur zwei Programme. Einer von ihnen enthält ein Objekt und der andere ruft Methoden für dieses Objekt auf. Methoden eines Objekts aufrufen, das in einem anderen Programm existiert – das haben wir noch nicht gemacht! Es ist Zeit, es auszuprobieren! :) Um nicht ins Stocken zu geraten, lassen Sie uns Halten Sie unser Programm einfach. Im Allgemeinen führt ein Server einige Berechnungen durch, die von einem Client angefordert werden. Und so wird es auch bei uns sein. Unser Server wird ein einfaches Taschenrechnerprogramm sein. Es wird nur eine Methode geben:multiply() . Es multipliziert zwei vom Client-Programm an es gesendete Zahlen und gibt dann das Ergebnis zurück. Zunächst benötigen wir eine Schnittstelle:

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Warum brauchen wir eine Schnittstelle? Denn RMI basiert auf der Erstellung von Proxys, die Sie in früheren Lektionen kennengelernt haben . Wie Sie sich wahrscheinlich erinnern, arbeiten wir mit Proxys über Schnittstellen, nicht über Klassen. Es gibt 2 wichtige Anforderungen an unsere Schnittstelle!
  1. Es muss die Remote-Schnittstelle erweitern.
  2. Alle seine Methoden müssen eine RemoteException auslösen (die IDE führt dies nicht automatisch aus – Sie müssen dies manuell hinzufügen!).
Jetzt müssen wir eine Serverklasse erstellen, die unsere Calculator- Schnittstelle implementiert. RMI in der Praxis – 2Auch hier ist alles ganz einfach:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
Hier gibt es eigentlich nichts zu kommentieren :) Jetzt müssen wir ein Serverprogramm schreiben, das unser Taschenrechnerobjekt konfiguriert und ausführt. Es wird so aussehen:

import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
Lassen Sie uns das herausfinden :) In der ersten Zeile deklarieren wir eine String-Variable:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
Diese Zeichenfolge ist der eindeutige Name des Remote-Objekts. Unser Client-Programm verwendet diesen Namen, um unseren Server zu finden: Sie werden dies später sehen. Als nächstes erstellen wir unser Rechnerobjekt:

final RemoteCalculationServer server = new RemoteCalculationServer();
Hier ist alles klar. Was als nächstes kommt, ist interessanter:

final Registry registry = LocateRegistry.createRegistry(2732);
Dieses Registry-Objekt ist eine Registry von Remote-Objekten. Das sind Objekte, auf die andere Programme aus der Ferne zugreifen können :) Wir haben die Nummer 2732 an die Methode LocateRegistry.createRegistry() übergeben . Dies ist die Portnummer – eine eindeutige Nummer, die andere Programme verwenden, um unsere Objektregistrierung zu finden (Sie werden dies wiederum unten sehen). Weiter geht es... Mal sehen, was in der nächsten Zeile passiert:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
In dieser Zeile erstellen wir einen Stub. Ein Stub kapselt den gesamten Remote-Aufruf. Sie können dies als das wichtigste Element von RMI betrachten. Was tut es?
  1. Es empfängt alle Informationen über einen Remote-Aufruf einer Methode.
  2. Wenn die Methode Parameter hat, deserialisiert der Stub diese. Achten Sie auf diesen Punkt! Die Argumente, die Sie an die remote aufgerufenen Methoden übergeben, müssen serialisierbar sein (schließlich werden sie über das Netzwerk übertragen). Für uns ist das kein Problem, wir übermitteln lediglich Zahlen. Vergessen Sie diese Anforderung jedoch nicht, wenn Sie Objekte übertragen!
  3. Danach ruft der Stub die gewünschte Methode auf.
Wir übergeben unser Taschenrechner-Serverobjekt an die Methode UnicastRemoteObject.exportObject() . Auf diese Weise ermöglichen wir den Remote-Aufruf seiner Methoden. Es bleibt nur noch eines zu tun:

registry.bind(UNIQUE_BINDING_NAME, stub);
Wir „registrieren“ unseren Stub in der Remote-Objekt-Registrierung unter dem Namen, den wir uns ganz am Anfang ausgedacht haben. Jetzt kann der Kunde es finden! Vielleicht ist Ihnen aufgefallen, dass wir den Hauptthread des Programms am Ende in den Ruhezustand versetzt haben:

Thread.sleep(Integer.MAX_VALUE);
Wir brauchen nur, dass der Server lange läuft. In der IDE werden wir gleichzeitig zwei main()- Methoden starten: erstens die main()-Methode des Servers (in der ServerMain- Klasse, die wir bereits geschrieben haben) und zweitens die main()-Methode des Clients (in der ClientMain- Klasse). worüber wir weiter unten schreiben werden). Es ist wichtig, dass das Serverprogramm nicht beendet wird, während wir den Client starten, also versetzen wir es einfach für eine lange Zeit in den Ruhezustand. Auf jeden Fall läuft es weiter :) Jetzt können wir die main()- Methode unseres Servers ausführen. Lassen Sie es laufen und warten Sie, bis das Client-Programm eine Methode aufruft :) Jetzt schreiben wir das Client-Programm! Es sendet Zahlen zur Multiplikation an unseren Server.

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
Es sieht einfach aus. Aber was ist hier los? Zunächst muss der Client den eindeutigen Namen des Objekts kennen, dessen Methoden er remote aufruft. Dementsprechend haben wir im Client-Programm den öffentlichen statischen finalen String UNIQUE_BINDING_NAME = "server.calculator"; Variable. Als nächstes erhalten wir in der Methode main() Zugriff auf das Register der Remote-Objekte. Dazu müssen wir die Methode LocateRegistry.getRegistry() aufrufen und die Portnummer übergeben, die zum Erstellen unserer Registrierung im ServerMain-Programm verwendet wurde (Port 2732; diese Nummer ist nur ein Beispiel – Sie können versuchen, eine andere Nummer zu verwenden):

final Registry registry = LocateRegistry.getRegistry(2732);
Jetzt müssen wir nur noch das gewünschte Objekt aus der Registry holen! Das ist einfach, denn wir kennen seinen einzigartigen Namen!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Achten Sie auf den Typguss. Wir wandeln das empfangene Objekt in die Calculator- Schnittstelle um, nicht in die RemoteCalculationServer- Klasse. Wie wir zu Beginn der Lektion gesagt haben, ist RMI auf einen Proxy angewiesen, sodass Remote-Aufrufe nur für die Methoden einer Schnittstelle und nicht für die Methoden einer Klasse verfügbar sind. Schließlich rufen wir aus der Ferne die multiply()- Methode für unser Objekt auf und geben das Ergebnis an die Konsole aus.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
Die main() -Methode der ServerMain- Klasse läuft bereits seit langer Zeit. Jetzt ist es an der Zeit, die main()- Methode im Client-Programm ( ClientMain ) auszuführen ! Konsolenausgabe:

600
Das ist es! Unser Programm (eigentlich zwei Programme!) hat getan, was es tun sollte :) Wenn Sie Zeit und Lust haben, können Sie dies etwas aufpeppen. Stellen Sie beispielsweise sicher, dass der Rechner die vier Standardarithmetikoperationen unterstützt und Zahlen nicht als primitive Typen, sondern als CalculationInstance(int x, int y) -Objekte übergeben. Wir sehen uns in der nächsten Lektion! :) :)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION