Java RMI - Краткое руководство
RMI означает Remote Method Invocation. Это механизм, который позволяет объекту, находящемуся в одной системе (JVM), обращаться / вызывать объект, работающий в другой JVM.
RMI используется для создания распределенных приложений; он обеспечивает удаленную связь между программами Java. Предоставляется в упаковке.java.rmi.
Архитектура приложения RMI
В приложении RMI мы пишем две программы: server program (находится на сервере) и client program (находится на клиенте).
Внутри серверной программы создается удаленный объект, и ссылка на этот объект становится доступной для клиента (с помощью реестра).
Клиентская программа запрашивает удаленные объекты на сервере и пытается вызвать их методы.
На следующей схеме показана архитектура приложения RMI.
Давайте теперь обсудим компоненты этой архитектуры.
Transport Layer- Этот уровень соединяет клиента и сервер. Он управляет существующим подключением, а также устанавливает новые подключения.
Stub- Заглушка - это представление (прокси) удаленного объекта на клиенте. Он находится в клиентской системе; он действует как шлюз для клиентской программы.
Skeleton - Это объект, который находится на стороне сервера. stub связывается с этим каркасом, чтобы передать запрос удаленному объекту.
RRL(Remote Reference Layer) - Это уровень, который управляет ссылками, сделанными клиентом на удаленный объект.
Работа приложения RMI
Следующие пункты суммируют, как работает приложение RMI.
Когда клиент обращается к удаленному объекту, он принимается заглушкой, которая в конечном итоге передает этот запрос в RRL.
Когда клиентский RRL получает запрос, он вызывает метод, называемый invoke() объекта remoteRef. Он передает запрос в RRL на стороне сервера.
RRL на стороне сервера передает запрос скелету (прокси на сервере), который, наконец, вызывает требуемый объект на сервере.
Результат полностью передается клиенту.
Маршаллинг и демаршаллинг
Каждый раз, когда клиент вызывает метод, который принимает параметры удаленного объекта, параметры объединяются в сообщение перед отправкой по сети. Эти параметры могут быть примитивного типа или объектами. В случае примитивного типа параметры объединяются и к ним прикрепляется заголовок. Если параметры являются объектами, они сериализуются. Этот процесс известен какmarshalling.
На стороне сервера упакованные параметры разделяются, а затем вызывается требуемый метод. Этот процесс известен какunmarshalling.
Реестр RMI
Реестр RMI - это пространство имен, в котором размещаются все объекты сервера. Каждый раз, когда сервер создает объект, он регистрирует этот объект в RMIregistry (используяbind() или же reBind()методы). Они зарегистрированы под уникальным именем, известным какbind name.
Чтобы вызвать удаленный объект, клиенту нужна ссылка на этот объект. В это время клиент извлекает объект из реестра, используя его имя привязки (используяlookup() метод).
Следующая иллюстрация объясняет весь процесс -
Цели RMI
Ниже приведены цели RMI -
- Чтобы минимизировать сложность приложения.
- Чтобы сохранить безопасность типа.
- Распределенная сборка мусора.
- Минимизируйте разницу между работой с локальными и удаленными объектами.
Чтобы написать приложение RMI Java, вам нужно будет выполнить следующие шаги:
- Определите удаленный интерфейс
- Разработать класс реализации (удаленный объект)
- Разработать серверную программу
- Разработать клиентскую программу
- Скомпилируйте приложение
- Запустить заявку
Определение удаленного интерфейса
Удаленный интерфейс предоставляет описание всех методов конкретного удаленного объекта. Клиент связывается с этим удаленным интерфейсом.
Чтобы создать удаленный интерфейс -
Создайте интерфейс, расширяющий предопределенный интерфейс Remote который принадлежит пакету.
Объявите все бизнес-методы, которые может вызывать клиент в этом интерфейсе.
Поскольку во время удаленных вызовов есть вероятность проблем с сетью, исключение с именем RemoteExceptionможет произойти; брось это.
Ниже приведен пример удаленного интерфейса. Здесь мы определили интерфейс с именемHello и у него есть метод, называемый printMsg().
import java.rmi.Remote;
import java.rmi.RemoteException;
// Creating Remote interface for our application
public interface Hello extends Remote {
void printMsg() throws RemoteException;
}
Разработка класса реализации (удаленный объект)
Нам нужно реализовать удаленный интерфейс, созданный на предыдущем шаге. (Мы можем написать класс реализации отдельно или напрямую заставить серверную программу реализовать этот интерфейс.)
Чтобы разработать класс реализации -
- Реализуйте интерфейс, созданный на предыдущем шаге.
- Обеспечьте реализацию всех абстрактных методов удаленного интерфейса.
Ниже приведен класс реализации. Здесь мы создали класс с именемImplExample и реализовал интерфейс Hello создан на предыдущем шаге и предоставлен body для этого метода, который печатает сообщение.
// 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");
}
}
Разработка серверной программы
Программа сервера RMI должна реализовывать удаленный интерфейс или расширять класс реализации. Здесь мы должны создать удаленный объект и привязать его кRMIregistry.
Для разработки серверной программы -
Создайте клиентский класс, из которого вы хотите вызвать удаленный объект.
Create a remote object путем создания экземпляра класса реализации, как показано ниже.
Экспортируйте удаленный объект с помощью метода exportObject() класса по имени UnicastRemoteObject который принадлежит пакету java.rmi.server.
Получите реестр RMI с помощью getRegistry() метод LocateRegistry класс, который принадлежит пакету java.rmi.registry.
Привяжите удаленный объект, созданный к реестру, используя bind() метод класса с именем Registry. В этот метод передайте строку, представляющую имя привязки и экспортируемый объект в качестве параметров.
Ниже приведен пример серверной программы 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();
}
}
}
Разработка клиентской программы
Напишите в нем клиентскую программу, выберите удаленный объект и вызовите требуемый метод, используя этот объект.
Для разработки клиентской программы -
Создайте клиентский класс, из которого вы собираетесь вызывать удаленный объект.
Получите реестр RMI с помощью getRegistry() метод LocateRegistry класс, который принадлежит пакету java.rmi.registry.
Получить объект из реестра с помощью метода lookup() класса Registry который принадлежит пакету java.rmi.registry.
В этот метод вам необходимо передать строковое значение, представляющее имя привязки, в качестве параметра. Это вернет вам удаленный объект.
Lookup () возвращает объект типа remote с приведением его к типу Hello.
Наконец, вызовите требуемый метод, используя полученный удаленный объект.
Ниже приведен пример клиентской программы 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();
}
}
}
Компиляция заявки
Для компиляции приложения -
- Скомпилируйте удаленный интерфейс.
- Скомпилируйте класс реализации.
- Скомпилируйте серверную программу.
- Скомпилируйте клиентскую программу.
Или же,
Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.
Javac *.java
Запуск приложения
Step 1 - Запустите rmi реестр с помощью следующей команды.
start rmiregistry
Это запустит rmi реестр в отдельном окне, как показано ниже.
Step 2 - Запустите файл класса сервера, как показано ниже.
Java Server
Step 3 - Запустите файл клиентского класса, как показано ниже.
java Client
Verification - Как только вы запустите клиент, вы увидите следующий вывод на сервере.
В предыдущей главе мы создали образец приложения RMI. В этой главе мы объясним, как создать приложение RMI, в котором клиент вызывает метод, отображающий окно графического интерфейса пользователя (JavaFX).
Определение удаленного интерфейса
Здесь мы определяем удаленный интерфейс с именем Hello с методом с именем animation() в этом.
import java.rmi.Remote;
import java.rmi.RemoteException;
// Creating Remote interface for our application
public interface Hello extends Remote {
void animation() throws RemoteException;
}
Разработка класса реализации
В классе реализации (удаленный объект) этого приложения мы пытаемся создать окно, которое отображает содержимое графического интерфейса пользователя, используя 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();
}
}
Серверная программа
Программа сервера RMI должна реализовывать удаленный интерфейс или расширять класс реализации. Здесь мы должны создать удаленный объект и привязать его кRMIregistry.
Ниже приводится серверная программа этого приложения. Здесь мы расширим созданный выше класс, создадим удаленный объект и зарегистрируем его в реестре RMI с именем привязки.hello.
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();
}
}
}
Клиентская программа
Ниже приводится клиентская программа этого приложения. Здесь мы получаем удаленный объект и вызываем его метод с именемanimation().
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();
}
}
}
Шаги по запуску примера
Ниже приведены шаги для запуска нашего примера RMI.
Step 1 - Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.
Javac *.java
Step 2 - Запустите rmi реестр с помощью следующей команды.
start rmiregistry
Это запустит rmi реестр в отдельном окне, как показано ниже.
Step 3 - Запустите файл класса сервера, как показано ниже.
Java Server
Step 4 - Запустите файл клиентского класса, как показано ниже.
java Client
Verification - Как только вы запустите клиент, вы увидите следующий вывод на сервере.
В предыдущей главе мы создали образец приложения RMI, в котором клиент вызывает метод, отображающий окно графического интерфейса пользователя (JavaFX).
В этой главе мы рассмотрим пример, чтобы увидеть, как клиентская программа может получить записи таблицы в базе данных MySQL, находящейся на сервере.
Предположим, у нас есть таблица с именем student_data в базе данных details как показано ниже.
+----+--------+--------+------------+---------------------+
| ID | NAME | BRANCH | PERCENTAGE | EMAIL |
+----+--------+--------+------------+---------------------+
| 1 | Ram | IT | 85 | [email protected] |
| 2 | Rahim | EEE | 95 | [email protected] |
| 3 | Robert | ECE | 90 | [email protected] |
+----+--------+--------+------------+---------------------+
Предположим, имя пользователя myuser и его пароль password.
Создание студенческого класса
Создать Student класс с setter и getter методы, как показано ниже.
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;
}
}
Определение удаленного интерфейса
Определите удаленный интерфейс. Здесь мы определяем удаленный интерфейс с именемHello с методом с именем getStudents ()в этом. Этот метод возвращает список, содержащий объект классаStudent.
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;
}
Разработка класса реализации
Создайте класс и реализуйте созданный выше interface.
Здесь мы реализуем getStudents() метод Remote interface. Когда вы вызываете этот метод, он извлекает записи из таблицы с именемstudent_data. Устанавливает эти значения в класс Student, используя его методы установки, добавляет его в объект списка и возвращает этот список.
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;
}
}
Серверная программа
Программа сервера RMI должна реализовывать удаленный интерфейс или расширять класс реализации. Здесь мы должны создать удаленный объект и привязать его кRMI registry.
Ниже приводится серверная программа этого приложения. Здесь мы расширим созданный выше класс, создадим удаленный объект и зарегистрируем его в реестре RMI с именем привязки.hello.
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();
}
}
}
Клиентская программа
Ниже представлена клиентская программа этого приложения. Здесь мы получаем удаленный объект и вызываем метод с именемgetStudents(). Он извлекает записи таблицы из объекта списка и отображает их.
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();
}
}
}
Шаги по запуску примера
Ниже приведены шаги для запуска нашего примера RMI.
Step 1 - Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.
Javac *.java
Step 2 - Запустите rmi реестр с помощью следующей команды.
start rmiregistry
Это запустит rmi реестр в отдельном окне, как показано ниже.
Step 3 - Запустите файл класса сервера, как показано ниже.
Java Server
Step 4 - Запустите файл клиентского класса, как показано ниже.
java Client