Java Remote Method Invocation RMI
Willemers Informatik-Ecke
In einigen Dokumentationen im Web wird rmic erwähnt. Der rmic ist ein RMI-Compiler, der dem JDK beiliegt. Er erzeugt aus den kommunizierenden Klassen stub bzw skeleton für die Kommunikation. Seit Java 1.5.0 ist er allerdings nicht mehr erforderlich, da der stub von der virtuellen Maschine übernommen wird. (vgl. Wikipedia-Artikel)

Ein kleines Beispiel

Das Interface des Servers

Der Fernaufruf basiert auf einem Interface, das Java.rmi.Remote erweitert. Der Server wird es implementieren und der Client aufrufen.
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ServerInterface extends Remote {
     public void bitteMeldeDich() throws RemoteException;
     public int gibZahl() throws RemoteException;
}
Dieses Interface wird nun vom Server implementiert.

Der RMI-Server

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

public class MeinServer extends UnicastRemoteObject implements ServerInterface {

    MeinServer() throws RemoteException {
        super();
    }

    public static void main(String[] args) {

        try {
            LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
            Naming.rebind("MeinServer", new MeinServer());
        } catch (MalformedURLException ex) {
            System.out.println(ex.getMessage());
        } catch (RemoteException ex) {
            System.out.println(ex.getMessage());
        }
    }
    // Die Remote veröffentlichten Methoden
    public void bitteMeldeDich() throws RemoteException  {
        System.out.println("Hier MeinServer!");
    }
    public int gibZahl() throws RemoteException  {
        System.out.println("Zahlenabwurf");
        return 42;
    }
}
Der Server erzeugt eine Registry auf der Standard-Portnummer und bindet sich unter dem Namen MeinServer an diesen Port. Ansonsten fängt er nur die möglichen Exceptions. Die beiden Methoden des Interfaces werden implementiert.

Der Server wird von der Konsole einfach gestartet und blockiert, ohne einen Ton von sich zu geben, sofern alles in Ordnung ist.

Ein RMI-Client

Der Client sucht nun nach dem Namen MeinServer in der lokalen Registry. Dann ruft er die beiden Methoden des Servers nacheinander auf.
import java.rmi.Naming;

public class MeinClient {

    public static void main(String[] args) {
        String url = "rmi://127.0.0.1/MeinServer";
        try {
            ServerInterface server = (ServerInterface) Naming.lookup(url);
            server.bitteMeldeDich();
            int zahl = server.gibZahl();
            System.out.println(zahl);
        } catch (Exception e) {
            System.err.println("Client Exception: " + e.toString());
            e.printStackTrace();
        }
    }
}
Der URL-String hat den allgemeinen Aufbau:
rmi://host:port/objekt
Wie oben gesehen, kann der Port entfallen.

Vor dem Start des Clients muss der Server natürlich gestartet sein. Der Start des Clients bewirkt, dass der Server auf seiner Konsole anzeigt, dass die beiden Methoden aufgerufen wurden. Der Client zeigt eine 42 als Zeichen, dass er die Zahl vom Server erhalten hat.

Anmerkungen

Komplexe Objekte werden für die Übermittlung serialisiert. Entsprechend müssen übertragbare Objekte die Schnittstelle Serializable implementieren.

Der Expert von Remote-Objekten wird durch die Klasse UnicastRemoteObject erreicht. Hier gibt es zwei Vorgehensweisen. Im hier vorgeführten Fall erweitert die Serverklasse die Klasse UnicastRemoteObject. Dann muss sie im Standardkonstruktor mit super() den Konstruktor der Basisklasse aufrufen. Diese muss dann auch die RemoteException werfen.

Alternativ kann auch das Server-Objekt mit der statischen Methode UnicastRemoteObject.exportObject exportiert werden. Der Rückgabewert ist ein Remote-Objekt-Stub, der als Parameter beim bind verwendet werden kann.

Wird die Registry über das Programm rmiregistry gestartet, muss dieser im Verzeichnis der Klassen des Servers gestartet werden oder durch die Option -Djava.rmi.server.codebase=file:/pfad auf dieses Verzeichnis verweisen.