Das RMI System besteht aus drei vollständig unabhängigen, eigenständigen Schichten: der stub/skeleton-layer, der remote reference-layer, und der transport-layer.
Die Kommunikation erfolgt im RMI automatisch über fest definierte Protokolle, so daß es auch stets möglich ist eine komplette Schicht auszutauschen. Z.B. kann die derzeit auf TCP basiernde Transportschicht evtl. durch eine andere Transportschicht ersetzt werden, die ein anderes Protokoll realisiert, z.B. UDP.
Die Zuordnung von Client- und Serverfunktion gilt stets nur für eine konkrete Kommunikation zweier Objekte. Somit kann ein Objekt Client bzgl. eines Zugriffs auf ein entferntes Serverobjekt sein und danach einen Serverdienst für ein anderes Objekt erbringen, welches auf einem anderen, entfernten Rechner existiert.
Der Aufruf einer entfernten Methode läuft nun von der Applikationsschicht des Clients hinunter durch die Schichten des RMI Systems zur Transportschicht, wird dann zum Server übertragen, und durchläuft serverseitig wieder durch die Schichten des RMI Systems, um vom Server abgearbeitet zu werden.
Die Stub/Skeleton-Schicht ist das Interface zwischen der Applikationsschicht und dem RMI System, sie kümmert sich nicht um spezielle Details des Datentransports, sondern überträgt die Daten zur und von der Remote Reference Schicht durch das Prinzip des "parameter marshalling". Wenn von einem Objekt im Client eine Methode eines Serverobjekts aufgerufen werden soll, bzw. dem Serverobjekt eine Nachricht gesendet werden soll, wird ein lokales Stellvertreterobjekt verwendet, welches als Stub bezeichnet wird. Dieses existiert im Adressraum der JVM die das Client-Objekt ausführt und stellt somit für die restliche Applikation ein reguläres Java-Objekt dar. Der Stub implementiert die Interfaces, welche auch vom entfernten Objekt unterstützt werden.
Auf der Serverseite empfängt das entfernte Stellvertreterobjekt des eigentlichen Remote-Objektes, bezeichnet als Skeleton, über die dortige Remote Reference Schicht den Datenblock und ruft die gewünschte Methode des Serverobjekts auf. Rückgabewerte, wozu auch ausgelöste Ausnahmeobjekte (Exceptions) gehören, werden auf analogem Weg zum Client zurückgesendet.
Die passenden Stub- und Skeleton Klassen werden zur Laufzeit bestimmt und dynamisch geladen(Dynamic class loading).
Da ein generelles Ziel vom RMI System eine nahtlose Eingliederung des APIs in die reguläre Sprache ist, kann der Entwickler die Remote-Objekte (fast) genauso verwenden wie originäre Java-Objekte. Damit ist auch klar, daß der oben beschriebene komplexe Kommunikationsweg vollständig transparent und vom RMI automatisiert ist.
In dieser Schicht wird die Kommunikation mit der Transportschicht geregelt und im wesentlichen das Protokoll bestimmt, nach dem die entfernten Referenzen zugeordnet werden. Dies geschieht unabhängig von den Stub- und Skeleton-Objekten.
Jede Implementierung eines entfernten Objekts bestimmt die Art der Referenzierung. Es können verschiedene Aufrufprotokolle in dieser Schicht umgesetzt werden:
Die Remote Reference Schicht sendet die Daten, durch abstrakte, streamorientierte Verbindungskanäle, zur Transportschicht. Und obwohl eine Verbindung durch Streams zustande kommt, kann die Verbindung durch die Abstraktion transparent implementiert werden.
In der Transportschicht werden die folgenden Aufgaben wahrgenommen:
Die Übertragung im RMI System geschieht mit Hilfe von vier grundlegenden Abstraktionsarten:
Die konkrete Repräsentierung eines entfernten Objekts, bezeichnet als live reference, besteht aus einem endpoint und einer eindeutigen Identifikation (Schlüssel) des Objekts. Mit einer solchen live reference kann in der Transportschicht im Client per endpoint die Verbindung zum entfernten Adressraum aufgebaut, sowie auf der Serverseite das konkrete Objekt durch den Schlüssel bestimmt werden.
Ein transport definiert wie eine konkrete Repräsentation eines endpoits aussieht, d.h. es können verschiedene Übertragungsmöglichkeiten implementiert werden, so daß mehrere Protokolle (TCP und UDP) in derselben JVM unterstützt werden können. Das RMI Transport Interface ist jedoch nur für die Implementation der VM verfügbar, und nicht direkt für die Applikation.
Ein Client im RPC-Umfeld benötigt kompilierten Code für Stubs, der statisch oder dynamisch (über lokale Bibliotheken oder ein Netzwerk-Filesystem) zum aktuellen Programm gebunden wird, bevor die Routine ausgeführt werden kann.
RMI generalisiert diese Technik dahingehend, daß
Zusätzlich zu den Class Loadern benutzt das dynamic class loading weitere Mechanismen, wie die Objekt Serialisation, um die Klassen über das Netz zu übertragen, sowie einen Security Manager der die geladenen Klassen überwacht. (--> Security)
In einem verteilten System, genau wie in einem lokalen System, ist es wünschenswert, entfernte Objekte die nicht mehr referenziert werden, automatisch zu löschen. Das befreit den Programmierer von der Verfolgung der entfernten Objekte, um sie manuell zu entfernen, damit das Programm sauber beendet werden kann.
Um die garbage collection aller Objekte zu ermöglichen, muß das RMI System zur Laufzeit alle live references innerhalb jeder JVM
verfolgen. Wenn eine live reference in eine JVM eintritt, wird ihr Referenzzähler erhöht. Die erste Referenz eines Objekts sendet eine
"referenzierte" Nachricht an den Server des Objekts. Durch die Beendigung einer live refernce in der lokalen VM, wird der Referenzzähler
erniedrigt. Wenn nun auch die letzte Referenz entfernt wurde, wird eine "unreferenzierte" Nachricht an den Server geschickt. Wie bei dem
Lebenszyklus eines normalen Objekts, wird die Methode finalize
aufgerufen, nachdem der Garbage Collector festgestellt hat, daß keine
Referenzen, weder lokal noch entfernt, auf das Objekt existieren.
Natürlich ist es im Netzzugriff nicht immer möglich, daß eine entfernte Objektreferenz aufgelöst werden kann
(durch Netzwerkausfall), wenn dann versucht wird eine solche Referenz zu benutzen, wird eine RemoteException
ausgelöst.
Im Bereich der Netzwerkanwendungen ist stets die Möglichkeit gegeben, daß Mißbrauch mit den Zugriffsmöglichkeiten betrieben wird. In dem konkreten Fall der verteilten Anwendungen ist eine Steuerung und Kontrolle der entfernten Methodenaufrufe notwendig. Das RMI-System bietet ein Standardsicherheitssystem an, den RMISecurityManager. Dieser muß in Applikationen als erstes gestartet werden, um die Kontrolle über die über Netz gehenden Methodenaufrufe zu erhalten und entscheiden zu können, welche Stub-Klassen von welchen Servern geladen werden dürfen. Auch kann dadurch kontrolliert werden, was Stub-Objekte, die ja im Adressraum des Clients ausgeführt werden, dürfen, z.B. Zugriff auf lokale Ressourcen (Festplatte, etc.) und Zugriff auf andere Server.
Werden RemoteObjects über Applets geladen, so übernimmt standardmäßig der Applet Security-Manager die Kontrolle. Es ist weiterhin möglich eigene Security-Manager zu implementieren, die speziell applikationsgebundene Sicherheitsbelange unterstützen. Wenn kein Security Manager spezifiziert wird, können keine Klassen über das Netz geladen werden.
Zudem ist seitens des Designs und der Entwicklung steuerbar, welche (entfernte) Objekte über das Netz transportiert werden können. Dies kann nur mit Objekten geschehen, die serialisierbar sind, also das Interface Serializable implementieren. Dies kann jedoch für jedes Applikationsobjekt selbständig deklariert werden.
Normalerweise versucht die RMI Transportschicht direkte Socketverbindungen zu anderen Hosts zu öffnen, jedoch gibt es viele Hosts die
dieses durch eine Firewall verhindern. Für diesen Fall besitzt das RMI System zwei alternative HTTP-basierende Mechanismen, die es einem
Client hinter einer Firewall erlauben, Methoden eines entfernten Objekts außerhalb dieser Firewall aufzurufen (POST-Anfragen oder Firewall
-tunneling durch RMISocketFactory
).