Java RMI - Beispiel für verteilte Objekte

Java RMI - Beispiel für verteilte Objekte

distributed_object_communication

Bildquelle:Wikimedia.org

InJava RMI Hello World example haben wirJava Remote Method Invocation mit einer sehr einfachenString-based-Kommunikation zwischen Server-Client eingeführt. In this example we will take it one small step further and introduce Server-Client communication using Distributed Objects.

1. Die Remote-Schnittstelle

Zuerst entwickeln wirRemote Interface, das alle vom Server implementierten Methoden enthält. DieInterface müssen immerpublic sein undRemote verlängern. Alle inRemote Interface beschriebenen Methoden müssenRemoteException in ihrer Throws-Klausel auflisten.

RMIInterface.java

package com.techfou.rmiinterface;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;

public interface RMIInterface extends Remote {

    Book findBook(Book b) throws RemoteException;
    List allBooks() throws RemoteException;

}

2. Die verteilte Objektklasse

Dies ist die Klasse derObject, die der Server und der Client austauschen, und muss dieSerializable Interface implementieren. Es ist auch äußerst wichtig, dass diese Klasse einen explizitenserialVersionUID-Wert deklariert, um die Konsistenz über verschiedene Java-Compiler-Implementierungen hinweg zu gewährleisten.

Wenn wir dies ignorieren oder wenn die Distributed Object-Klasse des Servers ein anderesserialVersionUID als die Distributed Object-Klasse des Clients deklariert, führt der Deserialisierungsprozess zu einemInvalidClassException.

In der Eclipse-IDE können Sie eine serialVersionUID wie folgt generieren:

java-rmi- distributed- objects-example-1

Book.java

package com.techfou.rmiinterface;

import java.io.Serializable;

public class Book implements Serializable {

    private static final long serialVersionUID = 1190476516911661470L;
    private String title;
    private String isbn;
    private double cost;

    public Book(String isbn) {
        this.isbn = isbn;
    }

    public Book(String title, String isbn, double cost) {
        this.title = title;
        this.isbn = isbn;
        this.cost = cost;
    }

    public String getTitle() {
        return title;
    }

    public String getIsbn() {
        return isbn;
    }

    public double getCost() {
        return cost;
    }

    public String toString() {
        return "> " + this.title + " ($" + this.cost + ")";
    }

}

3. Der Kellner

Der Server erweitertUnicastRemoteObject und implementiertRMIInterface. In der Hauptmethode binden wir den Server auf localhost mit dem Namen "MyBookstore". Der Einfachheit halber haben wir anstelle einer Datenbank oder einesFile die MethodeinitializeList() erstellt, die einList mitBook type Objects füllt, die die Bücher darstellen, über die unser Buchladen verfügt (… ja, nur 5) . Aber 5 tolle Bücher!).

Wir müssen auch einserialVersionUID für den Server hinzufügen, aber da der Server, den wir in diesem Beispiel entworfen haben, nur auf einem Computer existieren soll, müssen wir nicht zweimal darüber nachdenken, sondern können einfach eindefault serialVersionUIDfestlegen ) s. Wenn jedoch auch die Serverklasse verteilt wäre, müssten wir sicherstellen, dass dieserialVersionUID für die Klasse auf allen Plattformen, die sie implementiert haben, gleich sind.

Bookstore.java

package com.example.rmiserver;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

import com.example.rmiinterface.Book;
import com.example.rmiinterface.RMIInterface;

public class Bookstore extends UnicastRemoteObject implements RMIInterface {

    private static final long serialVersionUID = 1L;
    private List bookList;

    protected Bookstore(List list) throws RemoteException {
        super();
        this.bookList = list;
    }

    //The client sends a Book object with the isbn information on it
    //(note: it could be a string with the isbn too)

    //With this method the server searches in the List bookList
    //for any book that has that isbn and returns the whole object
    @Override
    public Book findBook(Book book) throws RemoteException {
        Predicate predicate = x -> x.getIsbn().equals(book.getIsbn());
        return bookList.stream().filter(predicate).findFirst().get();
    }

    @Override
    public List allBooks() throws RemoteException {
        return bookList;
    }

    private static List initializeList() {
        List list = new ArrayList<>();
        list.add(new Book("Head First Java, 2nd Edition", "978-0596009205", 31.41));
        list.add(new Book("Java In A Nutshell", "978-0596007737", 10.90));
        list.add(new Book("Java: The Complete Reference", "978-0071808552", 40.18));
        list.add(new Book("Head First Servlets and JSP", "978-0596516680", 35.41));
        list.add(new Book("Java Puzzlers: Traps, Pitfalls, and Corner Cases", "978-0321336781", 39.99));
        return list;
    }

    public static void main(String[] args) {
        try {
            Naming.rebind("//localhost/MyBookstore", new Bookstore(initializeList()));
            System.err.println("Server ready");
        } catch (Exception e) {
            System.err.println("Server exception: " + e.getMessage());
        }
    }

}

4. Der Kunde

Der Client "findet" den Server überRMIInterface Object, das nach einem Verweis auf das entfernte Objekt "sucht", das dem Namen zugeordnet ist, den wir als Parameter übergeben. Was wir gerade beschrieben haben, ist, wasNaming.lookup("//localhost/MyBookstore"); tut.

Der Rest des Codes für den Client dient nur dazu, ein funktionierendes Beispiel zu erstellen, mit dem Sie hoffentlich experimentieren können.

Customer.java

package com.example.rmiclient;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.List;
import java.util.NoSuchElementException;

import javax.swing.JOptionPane;

import com.example.rmiinterface.Book;
import com.example.rmiinterface.RMIInterface;

public class Customer {

    private static RMIInterface look_up;

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

        look_up = (RMIInterface) Naming.lookup("//localhost/MyBookstore");

        boolean findmore;
        do {

            String[] options = {"Show All", "Find a book", "Exit"};

            int choice = JOptionPane.showOptionDialog(null, "Choose an action", "Option dialog",
                    JOptionPane.DEFAULT_OPTION,
                    JOptionPane.INFORMATION_MESSAGE,
                    null, options, options[0]);

            switch (choice) {

                case 0:
                    List list = look_up.allBooks();
                    StringBuilder message = new StringBuilder();
                    list.forEach(x -> {
                        message.append(x.toString() + "\n");
                    });
                    JOptionPane.showMessageDialog(null, new String(message));
                    break;
                case 1:
                    String isbn = JOptionPane.showInputDialog("Type the isbn of the book you want to find.");
                    try {
                        Book response = look_up.findBook(new Book(isbn));
                        JOptionPane.showMessageDialog(null, "Title: " +
                                        response.getTitle() + "\n" + "Cost: $" +
                                        response.getCost(),
                                response.getIsbn(), JOptionPane.INFORMATION_MESSAGE);
                    } catch (NoSuchElementException ex) {
                        JOptionPane.showMessageDialog(null, "Not found");
                    }
                    break;
                default:
                    System.exit(0);
                    break;

            }
            findmore = (JOptionPane.showConfirmDialog(null, "Do you want to exit?", "Exit",
                    JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION);
        } while (findmore);
    }
}

5. Wie man es laufen lässt

5.1 After you create the four java files with your favorite IDE or Download the code below, navigate to your source folder as shown below.

java-rmi-distributed-objects-example-2

5.2 First thing we need to do is compile our sources. Führen Sie1. compileEverything.bat aus, wenn Sie den folgenden Code heruntergeladen haben, oder öffnen Sie ein Befehlsfenster in Ihrem Verzeichnis und führen Sie Folgendes aus:

Terminal

$ javac src/com/example/rmiinterface/RMIInterface.java src/com/example/rmiinterface/Book.java src/com/example/rmiserver/Bookstore.java src/com/example/rmiclient/Customer.java

5.3 Confirm that your sources were compiled by accessing their respective directories:

java-rmi-distributed-objects-example-3

5.4 Next we need to start the rmiregistry. Führen Sie entweder die2. startServer.bat erneut aus oder öffnen Sie ein Befehlsfenster und führen Sie Folgendes aus:

Terminal

$ cd src
$ start rmiregistry
$ java com.example.rmiserver.Bookstore

java-rmi-distributed-objects-example-4

5.5 If RmiRegistry started successfully, there will be another window that looks like this:

java-rmi-distributed-objects-example-5

5.6 Now we are ready to run our Client:

Öffnen Sie ein neues Eingabeaufforderungsfenster (oder führen Sie3. runClient.bat aus den heruntergeladenen Dateien aus) und führen Sie Folgendes aus:

Terminal

$ cd src
$ java com.example.rmiclient.Customer

5.6.1 The Customer class runs and prompts us for action:

java-rmi-distributed-objects-example-6

5.6.2 When we click “Show All” button:

java-rmi-distributed-objects-example-7

5.6.3 After clicking “OK” button:

java-rmi-distributed-objects-example-8

5.6.4 We click “No” button, since we don’t want to exit yet and the following dialog comes up. Wir geben eine ISBN ein (z. "978-0596009205") und klicken Sie auf "OK".

java-rmi-distributed-objects-example-9

5.6.5 If the book was found in the Server’s list:

java-rmi-distributed-objects-example-10

5.6.6 If it wasn’t found:

java-rmi-distributed-objects-example-11

5.6.7 The program will continue by asking us:

java-rmi-distributed-objects-example-8

Wenn wir auf "Ja" klicken, wird das Programm beendet. Wenn wir auf "Nein" klicken, kehren wir zum Hauptmenü zurück, um eine Aktion wie in 5.6.1 gezeigt auszuwählen.

Der Server läuft weiter, bis wir sein Fenster schließen. Auch nach dem Schließen des Clients können wir einen neuen oder sogar mehrere Clients öffnen, die gleichzeitig ausgeführt werden.

java-rmi- distributed- objects-example-12

Quellcode herunterladen

Herunterladen -RMIObjects.zip (5 KB)