Am einfachsten wäre es, wenn alle Komponenten auf demselben Heap-Speicherplatz derselben virtuellen Java-Maschine auf demselben Computer ausgeführt würden, aber in der Praxis sehen wir uns oft mit einer solchen Situation konfrontiert, wenn der Client nur ein Gerät ist, das Java ausführen kann Tun? Was passiert, wenn aus Sicherheitsgründen nur Programme auf dem Server auf die Datenbank zugreifen können?
Wir wissen, dass Methodenaufrufe in den meisten Fällen zwischen zwei Objekten auf demselben Heap erfolgen. Was ist, wenn Sie Methoden für Objekte auf verschiedenen Computern aufrufen möchten?
Normalerweise erhalten wir Informationen von einem Computer zu einem anderen Computer über den Eingabe-/Ausgabestrom des Sockets, öffnen die Socket-Verbindung des anderen Computers und rufen dann den Ausgabestrom ab, um die Daten zu schreiben. Wenn wir jedoch einen anderen Computer aufrufen möchten Computer, welche Methoden haben Objekte auf einer anderen Java Virtual Machine? Natürlich können wir das aufzurufende Kommunikationsprotokoll selbst definieren und entwerfen und die Ausführungsergebnisse dann über Socket zurückübertragen, und es kann auch so sein, als würden wir Methoden auf dem lokalen Computer aufrufen, das heißt, wenn wir entfernte Objekte aufrufen möchten (z wie andere Heaps), aber es sollte wie ein normaler Anruf sein.
Das ist es, was uns RMI bietet.
Das Design von Remote-Prozeduraufrufen
Es müssen vier Dinge erstellt werden: Server, Client, Server-Hilfseinrichtungen und Client-Hilfseinrichtungen.
1. Erstellen Sie Client- und Serveranwendungen. Die Serveranwendung ist ein Remote-Dienst, ein Objekt mit Methoden, die der Client aufruft.
2. Erstellen Sie client- und serverseitige Hilfsprogramme. Sie verarbeiten alle zugrunde liegenden Netzwerk-Eingabe-/Ausgabedetails des Clients und Servers, sodass es so aussieht, als würden Client und Programm lokale Aufrufe verarbeiten.
Aufgaben von Hilfseinrichtungen sind Objekte, die tatsächlich die Kommunikation durchführen. Sie geben dem Client das Gefühl, dass er ein lokales Objekt aufruft, aber in Wirklichkeit ruft es nur eine Methode A auf Proxy, der Socket- und Streaming-Details lokal verarbeitet. Auf der Serverseite verbinden die Hilfseinrichtungen des Servers die Anforderungen von den Client-Einrichtungen über den Socket, analysieren die gepackten Informationen und rufen dann den eigentlichen Dienst auf. Für das Dienstobjekt ist dies also After Beim Aufruf der Hilfseinrichtung vom lokalen Dienst erhält er den Rückgabewert, verpackt ihn und sendet ihn (über den Ausgabestrom des Sockets) an die Hilfseinrichtung des Clients zurück. Die Hilfseinrichtung des Clients entpackt die Informationen und überträgt sie an das Clientobjekt.
Der Prozess des Aufrufs einer Methode
1. Das Client-Objekt ruft doBigThing() für das Hilfseinrichtungsobjekt auf
2. Die Hilfseinrichtungen des Clients verpacken die Anrufinformationen und senden sie über das Netzwerk an die Hilfseinrichtungen des Servers.
3. Die serverseitige Hilfseinrichtung dekodiert die Informationen der clientseitigen Hilfseinrichtung und ruft damit den eigentlichen Dienst auf.
Das Diagramm, das diesen Prozess beschreibt, lautet wie folgt:
JavaRMI stellt clientseitige und serverseitige Hilfsobjekte bereit
In Java hat uns RMI dabei geholfen, clientseitige und serverseitige Hilfseinrichtungen zu erstellen. Mit anderen Worten: RMI weiß, wie man die gleichen Methoden für Client-Aufrufe bereitstellt . .
Darüber hinaus stellt RMI die gesamte für die Ausführung erforderliche Infrastruktur bereit, einschließlich Serviceabfragen und Hilfsfunktionen, die es Clients ermöglichen, Clients (echte Serviceagenten) zu finden und zu erhalten.
Bei Verwendung von RMI müssen keine Netzwerk- oder Eingabe-/Ausgabeprogramme geschrieben werden. Der Aufruf einer Remote-Methode durch den Client entspricht einem Methodenaufruf auf derselben virtuellen Java-Maschine.
Allgemeine Aufrufe unterscheiden sich ein wenig von RMI-Aufrufen. Für den Client sieht dieser Methodenaufruf zwar lokal aus, aber die Client-Hilfseinrichtung führt den Aufruf letztendlich über Sockets und Streams durch. und der Agent konvertiert sie in ein Remote-Protokoll. Wie die Zwischeninformationen von der Java Virtual Machine an die Java Virtual Machine gesendet werden, hängt vom Protokoll ab, das vom Hilfseinrichtungsobjekt verwendet wird.
Bei der Verwendung von RMI müssen Sie sich für das Protokoll entscheiden: JRMP oder IIOP ist das native Protokoll von RMI. Es ist für Remote-Aufrufe zwischen Java konzipiert. IIOP wird hingegen für den Aufruf von Java entwickelt. Für Objekte oder andere Arten von Remote-Methoden ist CORBA normalerweise problematischer als RMI, denn wenn beide Enden nicht Java sind, kommt es zu einer Reihe schrecklicher Übersetzungs- und Konversationsvorgänge.
Da wir uns nur um Java-zu-Java-Operationen kümmern, verwenden wir ein recht einfaches RMI.
In RMI werden die Hilfseinrichtungen auf der Clientseite als Stubs und die Hilfseinrichtungen auf der Serverseite als Skelette bezeichnet.
So erstellen Sie einen Remote-Dienst
1.Remote-Schnittstelle erstellen
Die Remote-Schnittstelle definiert die Methoden, die der Client remote aufrufen kann. Es handelt sich um eine polymorphe Klasse als Dienst. Sowohl der Stub als auch der Dienst implementieren diese Schnittstelle.
2. Implementieren Sie die Remote-Schnittstelle
Dies ist die eigentliche ausführende Klasse. Sie implementiert die auf der Schnittstelle definierten Methoden. Es ist das Objekt, das der Client aufruft.
3. Verwenden Sie rmic, um Stub und Skeleton zu generieren
Sowohl der Client als auch der Server müssen diese Klassen nicht erstellen oder den Quellcode dieser Klassen generieren. Dies wird automatisch gehandhabt, wenn das an das JDK angehängte rmic-Tool ausgeführt wird.
4. RMIregistry starten (rmiregistry)
rmiregistry ist wie ein Telefonbuch, der Benutzer erhält von hier aus den Proxy (das Stub-/Hilfsobjekt des Clients).
5. Starten Sie den Remote-Dienst
Das Dienstobjekt muss mit der Ausführung beginnen. Die Klasse, die den Dienst implementiert, startet die Dienstinstanz und registriert sie bei RMIRegistry. Erst nach der Registrierung kann sie dem Benutzer dienen.
Servercode
Schnittstelle definieren
/**
*
*MyRemote.java
*
* Funktion: TODO
* Klassenname: MyRemote.java
*
* ver. Aktualisierter Charakterhalter und neuer Inhalt.
*──────────────────────────────────────── ────
* V1.00 2013-3-19 Erste Version des Moduls Su Ruo
*
* Copyright (c) 2013 dennisit corporation Alle Rechte vorbehalten.
*
* E-Mail:<a href="mailto:[email protected]">E-Mail senden</a>
*
*
* Remote ist eine markierte Schnittstelle, was bedeutet, dass es keine Methoden gibt. Sie hat jedoch eine besondere Bedeutung für RMI, daher muss diese Regel befolgt werden.
* Beachten Sie, dass hier „extends“ verwendet wird und Schnittstellen andere Schnittstellen erben können.
*
*/
öffentliche Schnittstelle MyRemote erweitert Remote{
/**
* Die Remote-Schnittstelle definiert die Methoden, die der Client remote aufrufen kann. Es handelt sich um eine polymorphe Klasse als Dienst
* Mobilisieren Sie den Stub, der diese Schnittstelle implementiert. Da dieser Stub Netzwerk- und Ein-/Ausgabearbeiten durchführt, können verschiedene Dinge passieren
* Problem: Der Client behandelt oder deklariert Ausnahmen, um diese Art von Risiko zu erkennen. Wenn die Methode eine Ausnahme in der Schnittstelle deklariert, rufen Sie die Methode auf
* Alle Prozeduren müssen diese Ausnahme behandeln oder neu deklarieren.
*
* Die Parameter und Rückgabewerte von Remote-Methoden müssen primitiv oder serialisierbar sein
* Das Paket wird über das Netzwerk übertragen, und wenn es durch Serialisierung abgeschlossen ist, ist der Rückgabewert derselbe, wenn ein benutzerdefinierter Typ verwendet wird
*, es muss serialisiert sein
* @zurückkehren
* @throws RemoteException
* Alle Methoden in der Schnittstelle müssen RemoteException deklarieren
*/
public String sayHello() löst RemoteException aus;
}
/**
*
*MyRemoteImpl.java
*
* Funktion: TODO
* Klassenname: MyRemoteImpl.java
*
* ver. Aktualisierter Charakterhalter und neuer Inhalt.
*──────────────────────────────────────── ────
* V1.00 2013-3-19 Erste Version des Moduls Su Ruo
*
* Copyright (c) 2013 dennisit corporation Alle Rechte vorbehalten.
*
* E-Mail:<a href="mailto:[email protected]">E-Mail senden</a>
*
* Um ein Remote-Service-Objekt zu werden, muss das Objekt über remote-bezogene Funktionen verfügen. Die einfachste Methode besteht darin, UnicastRemoteObject zu erben
* (von java.rmi.server), damit diese übergeordnete Klasse die Arbeit erledigen kann
*
*/
Die öffentliche Klasse MyRemoteImpl erweitert UnicastRemoteObject und implementiert MyRemote{
/**
* Der Konstruktor der übergeordneten Klasse deklariert eine Ausnahme. Daher müssen Sie den Konstruktor schreiben, da dies bedeutet, dass Ihr Konstruktor riskanten Programmcode aufruft
*
* UnicastRemoteObject hat ein kleines Problem, sein Konstruktor löst eine RemoteException aus
* Deklarieren Sie einen Konstruktor für Ihre eigene Implementierung, damit es einen Ort gibt, an dem Sie RemoteException deklarieren können. Wenn die Klasse initialisiert wird, ist dies die übergeordnete Klasse
* Der Konstruktor wird definitiv aufgerufen. Wenn der Konstruktor der übergeordneten Klasse eine Ausnahme auslöst, löst der benutzerdefinierte Konstruktor, den wir ebenfalls deklarieren müssen, eine Ausnahme aus.
* @throws RemoteException
*/
protected MyRemoteImpl() löst RemoteException {
}
/**
* Implementieren Sie alle Methoden der ausgehenden Schnittstelle, müssen Sie jedoch keine RemoteException deklarieren
*/
@Override
öffentlicher String sayHello(){
return „Server sagt, RMI Hallo Welt!“;
}
public static void main(String[] args) {
versuchen {
/**
* Wir haben bereits einen Remote-Dienst und müssen Remote-Benutzern den Zugriff darauf ermöglichen. Dies kann durch Initialisieren und Hinzufügen zur RMI-Registrierung erfolgen.
* (Es muss ausgeführt werden, andernfalls schlägt das Programm fehl.) Beim Registrieren eines Objekts fügt das RMI-System den Stub zur Registrierung hinzu.
* Weil der Client dies benötigt, verwenden Sie rebind() von java.rmi.Naming, um den Dienst zu registrieren
*/
MyRemote-Dienst = new MyRemoteImpl();
/**
* Erstellen Sie ein Remote-Objekt und erstellen Sie dann mit static Naming.rebind() eine Zuordnung. Der registrierte Name wird für die Client-Abfrage bereitgestellt
*/
Naming.rebind("Remote Hello World", service);
} Catch (Ausnahme e) {
e.printStackTrace();
}
}
}
public void exec(){
versuchen {
/**
* Der Client muss das Stub-Objekt abrufen, da der Client seine Methode aufrufen muss. Dies hängt von der RMI-Registrierung ab
* Durchsuchen Sie dasselbe Verzeichnis, um Dienste mit übereinstimmenden Namen zu finden.
* Der Client fragt RMIRegistry ab und gibt das Stub-Objekt zurück
* Naming.lookup("rmi://127.0.0.1/Remote Hello World");
* Parameterbeschreibung
* rmi://127.0.0.1/Remote Hallo Welt
* 127.0.0.1 steht für den Hostnamen oder die Host-IP-Adresse
* Remote Hello World muss mit dem registrierten Namen identisch sein
*
*/
MyRemote service = (MyRemote)Naming.lookup("rmi://127.0.0.1/Remote Hello World");
String tmp = service.sayHello();
System.out.println(tmp);
} Catch (Ausnahme e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new MyRemoteClient().exec();
}
}
Das mit dem JDK gelieferte rmic-Tool generiert basierend auf der Dienstimplementierung zwei Klassen, Stub und Skeleton. Es fügt gemäß den Benennungsregeln _Stub oder _Skeleton nach dem Namen der Remote-Implementierung hinzu. rmic bietet mehrere Optionen, darunter das Nichtgenerieren von Skeletten, das Beobachten des Quellcodes der generierten Klassen oder die Verwendung von IIOP als Kommunikationsprotokoll. Denken Sie daran, dass rmic in der Lage sein muss, die implementierten Klassen zu finden. Daher müssen Sie möglicherweise rmic aus dem Verzeichnis ausführen, in dem sich die Implementierung befindet (in der Praxis müssen Sie möglicherweise die Struktur des Paketverzeichnisses und den vollständigen Namen berücksichtigen, der Einfachheit halber wird das Paket hier nicht verwendet).
Rufen Sie die Befehlszeile auf, um rmiregistry zu starten. Stellen Sie sicher, dass Sie es aus einem Verzeichnis starten, das auf die Klasse zugreifen kann. Am einfachsten ist es, es aus dem Verzeichnis der Klasse auszuführen.
Der laufende Screenshot sieht wie folgt aus
Beachten:
Der Client verwendet die Schnittstelle, um die Methode auf dem Stub aufzurufen. Die Java Virtual Machine des Clients muss über eine Stub-Klasse verfügen, aber der Client verweist nicht auf die Stub-Klasse im Programmcode. Der Client betreibt das reale Remote-Objekt immer über die Schnittstelle.
Der Server muss Stubs und Skeletons sowie Service- und Remote-Schnittstellen haben. Er erfordert die Stub-Klasse, da der Stub durch den echten Service ersetzt wird, der mit RMIRegistry verbunden ist.
Häufige Fehler bei der Verwendung von RMI:
1. Ich habe vergessen, rmiregistry vor dem Starten des Remote-Dienstes zu starten (rmiregistry muss gestartet werden, bevor Naming.rebind() zum Registrieren des Dienstes verwendet werden kann).
2. Ich habe vergessen, die Parameter und Rückgabetypen serialisierbar zu machen (dies wird während der Kompilierung nicht erkannt, sondern nur während der Ausführung).
3. Vergessen Sie, die Stub-Klasse an den Client zu übergeben
RMI eignet sich sehr gut zum Schreiben und Ausführen von Remote-Diensten, wir werden RMI jedoch nicht allein zum Ausführen von Website-Diensten verwenden. Wir benötigen mehr und bessere Funktionen wie Transaktionsverwaltung und gleichzeitige Verarbeitung in großem Maßstab. und Sicherheit und Datenbankverwaltung usw. Dies erfordert die Verwendung von EnterpriseApplicationServer.
Der JavaEE-Server umfasst einen Webserver und einen Enterprise JavaBeans (EJB)-Server. Der EJB-Server fungiert zwischen RMI-Aufrufen und der Serviceschicht.
Anwendung von RMI in JINI
Jini verwendet ebenfalls RMI (obwohl auch andere Protokolle verwendet werden können), verfügt jedoch über mehrere weitere Schlüsselfunktionen.
1. Adaptive Entdeckung
2. Selbstheilende Netzwerke
Der RMI-Client muss zunächst die Adresse und den Namen des Remote-Dienstes abrufen. Der Abfrageprogrammcode des Clients muss die IP-Adresse oder den Hostnamen des Remote-Dienstes (da sich RMIRegistry darauf befindet) und den vom Dienst registrierten Namen enthalten.
Bei der Verwendung von JINI müssen Benutzer jedoch nur eines wissen: die vom Dienst implementierte Schnittstelle.
Jini verwendet den Suchdienst, der stärker und anpassungsfähiger ist als RMIRegistry, da Jini automatisch im Netzwerk Werbung macht und die IP-Multicast-Technologie verwendet, um Informationen an das gesamte Netzwerk zu senden geht nach der Ausstrahlung des Abfragedienstes online, und der Client kann auch Nachrichten an das gesamte Netzwerk senden, um Anfragen zu stellen.
Wenn der Dienst online geht, durchsucht er dynamisch den JINI-Abfragedienst im Netzwerk und beantragt die Registrierung. Bei der Registrierung sendet der Dienst ein serialisiertes Objekt an den Abfragedienst Treiber des Netzwerkgeräts oder sogar der Dienst selbst, der auf dem Client ausgeführt werden kann. Und was registriert ist, ist die implementierte Schnittstelle.
Wie adaptive Exploration funktioniert
1. Der Jini-Abfragedienst startet im Netzwerk und nutzt die IP-Multicast-Technologie, um sich selbst zu bewerben
2. Ein anderer gestarteter Jini-Dienst versucht, sich beim neu gestarteten Abfragedienst zu registrieren. Er registriert die Funktion und nicht den Namen, d. h. die implementierte Schnittstelle, und sendet dann das serialisierte Objekt an den Abfragedienst.
3. Internetkunden möchten etwas zur Implementierung von ScientificCalculator bekommen, wissen aber nicht, wo sie es finden können, also fragen sie den Abfragedienst
4. Der Abfragedienst antwortet auf Abfrageergebnisse
Betrieb eines selbstheilenden Netzwerks
1. Für einen bestimmten Jini-Dienst ist eine Registrierung erforderlich. Neu registrierte Dienste müssen den Mietvertrag regelmäßig erneuern. Andernfalls geht der Abfragedienst davon aus, dass der Dienst offline ist vollständiger verfügbarer Service-Netzwerkstatus.
2. Der Dienst ist aufgrund des Herunterfahrens offline, sodass die Lease nicht aktualisiert wird und der Abfragedienst gestartet wird.