Java RMI –分散オブジェクトの例
画像ソース:Wikimedia.org
Java RMI Hello World
exampleでは、サーバーとクライアント間の非常に基本的なString-based
通信でJava Remote
Method Invocationを導入しました。 In this example we will take it one small step further and introduce Server-Client communication using Distributed Objects.
1. リモートインターフェース
最初に、サーバーが実装するすべてのメソッドを含むRemote Interface
を開発します。 Interface
は常にpublic
であり、Remote
を拡張する必要があります。 Remote Interface
で説明されているすべてのメソッドは、throws節にRemoteException
をリストする必要があります。
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; ListallBooks() throws RemoteException; }
2. 分散オブジェクトクラス
これは、サーバーとクライアントが交換するObject
のクラスであり、Serializable Interface
を実装する必要があります。 また、このクラスが明示的なserialVersionUID
値を宣言して、さまざまなJavaコンパイラ実装間の一貫性を保証することも非常に重要です。
これを無視した場合、またはサーバーの分散オブジェクトクラスがクライアントの分散オブジェクトクラスとは異なるserialVersionUID
を宣言した場合、逆シリアル化プロセスの結果はInvalidClassException
になります。
Eclipse IDEでは、次のようなserialVersionUIDを生成できます。
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. サーバー
サーバーはUnicastRemoteObject
を拡張し、RMIInterface
を実装します。 メインメソッドでは、localhost上のサーバーを「MyBookstore」という名前でバインドします。 簡単にするために、データベースやFile
を使用する代わりに、書店が持っている本を表すBook type Objects
でList
を埋めるメソッドinitializeList()
を作成しました(…はいのみ5 。 しかし、5つの素晴らしい本!)。
サーバーにもserialVersionUID
を追加する必要がありますが、この例で設計したサーバーは1台のマシンにのみ存在することを意図しているため、2回考える必要はないため、%(t1 )s。 ただし、サーバークラスも配布されている場合は、クラスのserialVersionUID
が実装されているすべてのプラットフォームで同じであることを確認する必要があります。
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 ListbookList; 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. クライアント
クライアントは、パラメータとして渡した名前に関連付けられたリモートオブジェクトへの参照を「検索」するRMIInterface Object
を介してサーバーを「検索」します。 今説明したのは、Naming.lookup("//localhost/MyBookstore");
が行うことです。
クライアント用の残りのコードは、うまくいけば実験できる実用的な例を作成するためのものです。
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: Listlist = 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. 実行方法
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.
5.2 First thing we need to do is compile our sources. 以下のコードをダウンロードした場合は1. compileEverything.bat
を実行するか、ディレクトリでコマンドウィンドウを開いて実行します。
ターミナル
$ 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:
5.4 Next we need to start the rmiregistry. 再度、2. startServer.bat
を実行するか、コマンドウィンドウを開いて次を実行します。
ターミナル
$ cd src $ start rmiregistry $ java com.example.rmiserver.Bookstore
5.5 If RmiRegistry started successfully, there will be another window that looks like this:
5.6 Now we are ready to run our Client:
新しいコマンドプロンプトウィンドウを開き(またはダウンロードしたファイルから3. runClient.bat
を実行し)、次のコマンドを実行します。
ターミナル
$ cd src $ java com.example.rmiclient.Customer
5.6.1 The Customer class
runs and prompts us for action:
5.6.2 When we click “Show All” button:
5.6.3 After clicking “OK” button:
5.6.4 We click “No” button, since we don’t want to exit yet and the following dialog comes up. ISBNを入力します(例: 「978-0596009205」)、「OK」をクリックします。
5.6.5 If the book was found in the Server’s list:
5.6.6 If it wasn’t found:
5.6.7 The program will continue by asking us:
「はい」ボタンをクリックすると、プログラムは終了します。 [いいえ]をクリックすると、メインメニューに戻り、5.6.1に示すアクションを選択します。
サーバーは、ウィンドウを閉じるまで稼働し続けます。 クライアントを閉じた後でも、同時に実行する新しいクライアントまたは複数のクライアントを開くことができます。
ソースコードをダウンロード
ダウンロード–RMIObjects.zip(5 KB)