Java RMI - szybki przewodnik
RMI oznacza Remote Method Invocation. Jest to mechanizm, który umożliwia obiektowi znajdującemu się w jednym systemie (JVM) dostęp do obiektu działającego na innej maszynie JVM / wywołanie go.
RMI służy do tworzenia aplikacji rozproszonych; zapewnia zdalną komunikację między programami Java. Jest dostarczany w pakieciejava.rmi.
Architektura aplikacji RMI
W aplikacji RMI piszemy dwa programy, a server program (znajduje się na serwerze) i client program (rezyduje na kliencie).
W programie serwera tworzony jest zdalny obiekt, a referencja do niego jest udostępniana klientowi (za pomocą rejestru).
Program klienta żąda zdalnych obiektów na serwerze i próbuje wywołać swoje metody.
Poniższy diagram przedstawia architekturę aplikacji RMI.
Omówmy teraz składniki tej architektury.
Transport Layer- Ta warstwa łączy klienta i serwer. Zarządza istniejącym połączeniem, a także tworzy nowe połączenia.
Stub- Odcinek jest reprezentacją (proxy) zdalnego obiektu na kliencie. Znajduje się w systemie klienta; działa jako brama dla programu klienta.
Skeleton - To jest obiekt znajdujący się po stronie serwera. stub komunikuje się z tym szkieletem, aby przekazać żądanie do zdalnego obiektu.
RRL(Remote Reference Layer) - Jest to warstwa, która zarządza odwołaniami klienta do zdalnego obiektu.
Działanie aplikacji RMI
Poniższe punkty podsumowują sposób działania aplikacji RMI -
Kiedy klient wywołuje zdalny obiekt, jest ono odbierane przez kod pośredniczący, który ostatecznie przekazuje to żądanie do RRL.
Gdy RRL po stronie klienta odbiera żądanie, wywołuje metodę o nazwie invoke() obiektu remoteRef. Przekazuje żądanie do RRL po stronie serwera.
RRL po stronie serwera przekazuje żądanie do szkieletu (proxy na serwerze), który ostatecznie wywołuje wymagany obiekt na serwerze.
Wynik jest przekazywany z powrotem do klienta.
Marshalling i Unmarshalling
Za każdym razem, gdy klient wywołuje metodę, która akceptuje parametry na zdalnym obiekcie, parametry są pakowane w wiadomość przed wysłaniem przez sieć. Te parametry mogą być prymitywnym typem lub obiektami. W przypadku typu pierwotnego parametry są łączone i dołączany jest do nich nagłówek. W przypadku, gdy parametry są obiektami, są serializowane. Ten proces jest znany jakomarshalling.
Po stronie serwera spakowane parametry są uwalniane, a następnie wywoływana jest wymagana metoda. Ten proces jest znany jakounmarshalling.
Rejestr RMI
Rejestr RMI to przestrzeń nazw, w której umieszczane są wszystkie obiekty serwera. Za każdym razem, gdy serwer tworzy obiekt, rejestruje go w rejestrze RMI (przy użyciubind() lub reBind()metody). Są one rejestrowane przy użyciu unikalnej nazwy znanej jakobind name.
Aby wywołać obiekt zdalny, klient potrzebuje odwołania do tego obiektu. W tym czasie klient pobiera obiekt z rejestru przy użyciu jego nazwy powiązania (przy użyciulookup() metoda).
Poniższa ilustracja wyjaśnia cały proces -
Cele RMI
Oto cele RMI -
- Aby zminimalizować złożoność aplikacji.
- Aby zachować bezpieczeństwo typu.
- Rozproszone wyrzucanie elementów bezużytecznych.
- Zminimalizuj różnicę między pracą z obiektami lokalnymi i zdalnymi.
Aby napisać aplikację RMI Java, musisz wykonać kroki podane poniżej -
- Zdefiniuj interfejs zdalny
- Opracuj klasę implementacji (obiekt zdalny)
- Opracuj program serwera
- Opracuj program klienta
- Skompiluj aplikację
- Uruchom aplikację
Definiowanie interfejsu zdalnego
Zdalny interfejs zawiera opis wszystkich metod określonego zdalnego obiektu. Klient komunikuje się z tym zdalnym interfejsem.
Aby utworzyć zdalny interfejs -
Utwórz interfejs, który rozszerza wstępnie zdefiniowany interfejs Remote który należy do pakietu.
Zadeklaruj wszystkie metody biznesowe, które mogą być wywoływane przez klienta w tym interfejsie.
Ponieważ istnieje możliwość wystąpienia problemów z siecią podczas połączeń zdalnych, nazwano wyjątek RemoteExceptionmoże wystąpić; wyrzuć to.
Poniżej znajduje się przykład zdalnego interfejsu. Tutaj zdefiniowaliśmy interfejs o nazwieHello i ma metodę o nazwie printMsg().
import java.rmi.Remote;
import java.rmi.RemoteException;
// Creating Remote interface for our application
public interface Hello extends Remote {
void printMsg() throws RemoteException;
}
Opracowanie klasy implementacji (obiekt zdalny)
Musimy zaimplementować zdalny interfejs utworzony we wcześniejszym kroku. (Możemy osobno napisać klasę implementacji lub bezpośrednio sprawić, by program serwera implementował ten interfejs.)
Aby opracować klasę implementacji -
- Zaimplementuj interfejs utworzony w poprzednim kroku.
- Zapewnij implementację wszystkich abstrakcyjnych metod interfejsu zdalnego.
Poniżej znajduje się klasa implementacji. Tutaj stworzyliśmy klasę o nazwieImplExample i zaimplementował interfejs Hello utworzone w poprzednim kroku i dostarczone body dla tej metody, która drukuje wiadomość.
// Implementing the remote interface
public class ImplExample implements Hello {
// Implementing the interface method
public void printMsg() {
System.out.println("This is an example RMI program");
}
}
Opracowywanie programu serwera
Program serwera RMI powinien implementować zdalny interfejs lub rozszerzać klasę implementacji. Tutaj powinniśmy utworzyć zdalny obiekt i powiązać go z plikiemRMIregistry.
Aby opracować program serwera -
Utwórz klasę klienta, z której chcesz wywołać obiekt zdalny.
Create a remote object tworząc instancję klasy implementacji, jak pokazano poniżej.
Wyeksportuj zdalny obiekt przy użyciu metody exportObject() klasy o nazwie UnicastRemoteObject który należy do pakietu java.rmi.server.
Pobierz rejestr RMI przy użyciu rozszerzenia getRegistry() metoda LocateRegistry klasa należąca do pakietu java.rmi.registry.
Powiąż zdalny obiekt utworzony w rejestrze przy użyciu rozszerzenia bind() metoda klasy o nazwie Registry. Do tej metody jako parametry przekaż łańcuch reprezentujący nazwę powiązania i wyeksportowany obiekt.
Poniżej znajduje się przykład programu serwera RMI.
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server extends ImplExample {
public Server() {}
public static void main(String args[]) {
try {
// Instantiating the implementation class
ImplExample obj = new ImplExample();
// Exporting the object of implementation class
// (here we are exporting the remote object to the stub)
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);
// Binding the remote object (stub) in the registry
Registry registry = LocateRegistry.getRegistry();
registry.bind("Hello", stub);
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
}
Opracowanie programu klienckiego
Napisz w nim program kliencki, pobierz zdalny obiekt i wywołaj wymaganą metodę przy użyciu tego obiektu.
Aby opracować program klienta -
Utwórz klasę klienta, z której zamierzasz wywołać obiekt zdalny.
Pobierz rejestr RMI przy użyciu rozszerzenia getRegistry() metoda LocateRegistry klasa należąca do pakietu java.rmi.registry.
Pobierz obiekt z rejestru przy użyciu metody lookup() klasy Registry który należy do pakietu java.rmi.registry.
Do tej metody należy przekazać wartość ciągu reprezentującą nazwę powiązania jako parametr. To zwróci ci zdalny obiekt.
Funkcja lookup () zwraca obiekt typu remote i rzutuje go na typ Hello.
Na koniec wywołaj wymaganą metodę przy użyciu uzyskanego zdalnego obiektu.
Poniżej znajduje się przykład programu klienckiego RMI.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
private Client() {}
public static void main(String[] args) {
try {
// Getting the registry
Registry registry = LocateRegistry.getRegistry(null);
// Looking up the registry for the remote object
Hello stub = (Hello) registry.lookup("Hello");
// Calling the remote method using the obtained object
stub.printMsg();
// System.out.println("Remote method invoked");
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
}
Kompilowanie aplikacji
Aby skompilować aplikację -
- Skompiluj zdalny interfejs.
- Skompiluj klasę implementacji.
- Skompiluj program serwera.
- Skompiluj program klienta.
Lub,
Otwórz folder, w którym zapisałeś wszystkie programy i skompiluj wszystkie pliki Java, jak pokazano poniżej.
Javac *.java
Wykonywanie aplikacji
Step 1 - Uruchom rmi rejestru za pomocą następującego polecenia.
start rmiregistry
To rozpocznie rmi rejestru w osobnym oknie, jak pokazano poniżej.
Step 2 - Uruchom plik klasy serwera, jak pokazano poniżej.
Java Server
Step 3 - Uruchom plik klasy klienta, jak pokazano poniżej.
java Client
Verification - Zaraz po uruchomieniu klienta na serwerze pojawią się następujące dane wyjściowe.
W poprzednim rozdziale stworzyliśmy przykładową aplikację RMI. W tym rozdziale wyjaśnimy, jak utworzyć aplikację RMI, w której klient wywołuje metodę wyświetlającą okno GUI (JavaFX).
Definiowanie interfejsu zdalnego
Tutaj definiujemy zdalny interfejs o nazwie Hello z metodą o nazwie animation() w tym.
import java.rmi.Remote;
import java.rmi.RemoteException;
// Creating Remote interface for our application
public interface Hello extends Remote {
void animation() throws RemoteException;
}
Opracowanie klasy implementacyjnej
W klasie Implementation (Remote Object) tej aplikacji próbujemy utworzyć okno, które wyświetla zawartość GUI, używając JavaFX.
import javafx.animation.RotateTransition;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
// Implementing the remote interface
public class FxSample extends Application implements Hello {
@Override
public void start(Stage stage) {
// Drawing a Box
Box box = new Box();
// Setting the properties of the Box
box.setWidth(150.0);
box.setHeight(150.0);
box.setDepth(100.0);
// Setting the position of the box
box.setTranslateX(350);
box.setTranslateY(150);
box.setTranslateZ(50);
// Setting the text
Text text = new Text(
"Type any letter to rotate the box, and click on the box to stop the rotation");
// Setting the font of the text
text.setFont(Font.font(null, FontWeight.BOLD, 15));
// Setting the color of the text
text.setFill(Color.CRIMSON);
// Setting the position of the text
text.setX(20);
text.setY(50);
// Setting the material of the box
PhongMaterial material = new PhongMaterial();
material.setDiffuseColor(Color.DARKSLATEBLUE);
// Setting the diffuse color material to box
box.setMaterial(material);
// Setting the rotation animation to the box
RotateTransition rotateTransition = new RotateTransition();
// Setting the duration for the transition
rotateTransition.setDuration(Duration.millis(1000));
// Setting the node for the transition
rotateTransition.setNode(box);
// Setting the axis of the rotation
rotateTransition.setAxis(Rotate.Y_AXIS);
// Setting the angle of the rotation
rotateTransition.setByAngle(360);
// Setting the cycle count for the transition
rotateTransition.setCycleCount(50);
// Setting auto reverse value to false
rotateTransition.setAutoReverse(false);
// Creating a text filed
TextField textField = new TextField();
// Setting the position of the text field
textField.setLayoutX(50);
textField.setLayoutY(100);
// Handling the key typed event
EventHandler<KeyEvent> eventHandlerTextField = new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
// Playing the animation
rotateTransition.play();
}
};
// Adding an event handler to the text feld
textField.addEventHandler(KeyEvent.KEY_TYPED, eventHandlerTextField);
// Handling the mouse clicked event(on box)
EventHandler<javafx.scene.input.MouseEvent> eventHandlerBox =
new EventHandler<javafx.scene.input.MouseEvent>() {
@Override
public void handle(javafx.scene.input.MouseEvent e) {
rotateTransition.stop();
}
};
// Adding the event handler to the box
box.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, eventHandlerBox);
// Creating a Group object
Group root = new Group(box, textField, text);
// Creating a scene object
Scene scene = new Scene(root, 600, 300);
// Setting camera
PerspectiveCamera camera = new PerspectiveCamera(false);
camera.setTranslateX(0);
camera.setTranslateY(0);
camera.setTranslateZ(0);
scene.setCamera(camera);
// Setting title to the Stage
stage.setTitle("Event Handlers Example");
// Adding scene to the stage
stage.setScene(scene);
// Displaying the contents of the stage
stage.show();
}
// Implementing the interface method
public void animation() {
launch();
}
}
Program serwera
Program serwera RMI powinien implementować zdalny interfejs lub rozszerzać klasę implementacji. Tutaj powinniśmy utworzyć zdalny obiekt i powiązać go z plikiemRMIregistry.
Poniżej znajduje się program serwera tej aplikacji. Tutaj rozszerzymy wyżej utworzoną klasę, utworzymy zdalny obiekt i zarejestrujemy go w rejestrze RMI pod nazwą wiązaniahello.
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server extends FxSample {
public Server() {}
public static void main(String args[]) {
try {
// Instantiating the implementation class
FxSample obj = new FxSample();
// Exporting the object of implementation class
// (here we are exporting the remote object to the stub)
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);
// Binding the remote object (stub) in the registry
Registry registry = LocateRegistry.getRegistry();
registry.bind("Hello", stub);
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
}
Program klienta
Poniżej znajduje się program kliencki tej aplikacji. Tutaj pobieramy zdalny obiekt i wywołujemy jego metodę o nazwieanimation().
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
private Client() {}
public static void main(String[] args) {
try {
// Getting the registry
Registry registry = LocateRegistry.getRegistry(null);
// Looking up the registry for the remote object
Hello stub = (Hello) registry.lookup("Hello");
// Calling the remote method using the obtained object
stub.animation();
System.out.println("Remote method invoked");
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
}
Kroki do uruchomienia przykładu
Poniżej przedstawiono kroki, aby uruchomić nasz przykład RMI.
Step 1 - Otwórz folder, w którym zapisałeś wszystkie programy i skompiluj wszystkie pliki Java, jak pokazano poniżej.
Javac *.java
Step 2 - Uruchom rmi rejestru za pomocą następującego polecenia.
start rmiregistry
To rozpocznie rmi rejestru w osobnym oknie, jak pokazano poniżej.
Step 3 - Uruchom plik klasy serwera, jak pokazano poniżej.
Java Server
Step 4 - Uruchom plik klasy klienta, jak pokazano poniżej.
java Client
Verification - Zaraz po uruchomieniu klienta na serwerze pojawią się następujące dane wyjściowe.
W poprzednim rozdziale stworzyliśmy przykładową aplikację RMI, w której klient wywołuje metodę wyświetlającą okno GUI (JavaFX).
W tym rozdziale weźmiemy przykład, aby zobaczyć, jak program kliencki może pobrać rekordy tabeli w bazie danych MySQL znajdującej się na serwerze.
Załóżmy, że mamy tabelę o nazwie student_data w bazie danych details jak pokazano niżej.
+----+--------+--------+------------+---------------------+
| ID | NAME | BRANCH | PERCENTAGE | EMAIL |
+----+--------+--------+------------+---------------------+
| 1 | Ram | IT | 85 | [email protected] |
| 2 | Rahim | EEE | 95 | [email protected] |
| 3 | Robert | ECE | 90 | [email protected] |
+----+--------+--------+------------+---------------------+
Załóżmy, że nazwa użytkownika to myuser a jego hasło to password.
Tworzenie klasy studenckiej
Stwórz Student klasa z setter i getter metody, jak pokazano poniżej.
public class Student implements java.io.Serializable {
private int id, percent;
private String name, branch, email;
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getBranch() {
return branch;
}
public int getPercent() {
return percent;
}
public String getEmail() {
return email;
}
public void setID(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setBranch(String branch) {
this.branch = branch;
}
public void setPercent(int percent) {
this.percent = percent;
}
public void setEmail(String email) {
this.email = email;
}
}
Definiowanie interfejsu zdalnego
Zdefiniuj interfejs zdalny. Tutaj definiujemy zdalny interfejs o nazwieHello z metodą o nazwie getStudents ()w tym. Ta metoda zwraca listę zawierającą obiekt klasyStudent.
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.*;
// Creating Remote interface for our application
public interface Hello extends Remote {
public List<Student> getStudents() throws Exception;
}
Opracowanie klasy implementacyjnej
Utwórz klasę i zaimplementuj powyższy utworzony interface.
Tutaj wdrażamy getStudents() metoda Remote interface. Po wywołaniu tej metody pobiera rekordy tabeli o nazwiestudent_data. Ustawia te wartości na klasę Student przy użyciu jej metod ustawiających, dodaje je do obiektu listy i zwraca tę listę.
import java.sql.*;
import java.util.*;
// Implementing the remote interface
public class ImplExample implements Hello {
// Implementing the interface method
public List<Student> getStudents() throws Exception {
List<Student> list = new ArrayList<Student>();
// JDBC driver name and database URL
String JDBC_DRIVER = "com.mysql.jdbc.Driver";
String DB_URL = "jdbc:mysql://localhost:3306/details";
// Database credentials
String USER = "myuser";
String PASS = "password";
Connection conn = null;
Statement stmt = null;
//Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
//Open a connection
System.out.println("Connecting to a selected database...");
conn = DriverManager.getConnection(DB_URL, USER, PASS);
System.out.println("Connected database successfully...");
//Execute a query
System.out.println("Creating statement...");
stmt = conn.createStatement();
String sql = "SELECT * FROM student_data";
ResultSet rs = stmt.executeQuery(sql);
//Extract data from result set
while(rs.next()) {
// Retrieve by column name
int id = rs.getInt("id");
String name = rs.getString("name");
String branch = rs.getString("branch");
int percent = rs.getInt("percentage");
String email = rs.getString("email");
// Setting the values
Student student = new Student();
student.setID(id);
student.setName(name);
student.setBranch(branch);
student.setPercent(percent);
student.setEmail(email);
list.add(student);
}
rs.close();
return list;
}
}
Program serwera
Program serwera RMI powinien implementować zdalny interfejs lub rozszerzać klasę implementacji. Tutaj powinniśmy utworzyć zdalny obiekt i powiązać go z plikiemRMI registry.
Poniżej znajduje się program serwera tej aplikacji. Tutaj rozszerzymy wyżej utworzoną klasę, utworzymy zdalny obiekt i zarejestrujemy go w rejestrze RMI pod nazwą wiązaniahello.
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server extends ImplExample {
public Server() {}
public static void main(String args[]) {
try {
// Instantiating the implementation class
ImplExample obj = new ImplExample();
// Exporting the object of implementation class (
here we are exporting the remote object to the stub)
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);
// Binding the remote object (stub) in the registry
Registry registry = LocateRegistry.getRegistry();
registry.bind("Hello", stub);
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
}
Program klienta
Poniżej znajduje się program kliencki tej aplikacji. Tutaj pobieramy zdalny obiekt i wywołujemy nazwaną metodęgetStudents(). Pobiera rekordy tabeli z obiektu listy i wyświetla je.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.*;
public class Client {
private Client() {}
public static void main(String[] args)throws Exception {
try {
// Getting the registry
Registry registry = LocateRegistry.getRegistry(null);
// Looking up the registry for the remote object
Hello stub = (Hello) registry.lookup("Hello");
// Calling the remote method using the obtained object
List<Student> list = (List)stub.getStudents();
for (Student s:list)v {
// System.out.println("bc "+s.getBranch());
System.out.println("ID: " + s.getId());
System.out.println("name: " + s.getName());
System.out.println("branch: " + s.getBranch());
System.out.println("percent: " + s.getPercent());
System.out.println("email: " + s.getEmail());
}
// System.out.println(list);
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
}
Kroki do uruchomienia przykładu
Poniżej przedstawiono kroki, aby uruchomić nasz przykład RMI.
Step 1 - Otwórz folder, w którym zapisałeś wszystkie programy i skompiluj wszystkie pliki Java, jak pokazano poniżej.
Javac *.java
Step 2 - Uruchom rmi rejestru za pomocą następującego polecenia.
start rmiregistry
To rozpocznie rmi rejestru w osobnym oknie, jak pokazano poniżej.
Step 3 - Uruchom plik klasy serwera, jak pokazano poniżej.
Java Server
Step 4 - Uruchom plik klasy klienta, jak pokazano poniżej.
java Client