Java RMI — Введение
RMI обозначает дистанционный вызов метода . Это механизм, который позволяет объекту, находящемуся в одной системе (JVM), получать доступ / вызывать объект, запущенный в другой JVM.
RMI используется для создания распределенных приложений; он обеспечивает удаленную связь между Java-программами. Это предусмотрено в пакете java.rmi .
Архитектура приложения RMI
В приложении RMI мы пишем две программы: серверную (на сервере) и клиентскую (на клиенте).
-
Внутри серверной программы создается удаленный объект, и ссылка на этот объект становится доступной для клиента (с использованием реестра).
-
Клиентская программа запрашивает удаленные объекты на сервере и пытается вызвать его методы.
Внутри серверной программы создается удаленный объект, и ссылка на этот объект становится доступной для клиента (с использованием реестра).
Клиентская программа запрашивает удаленные объекты на сервере и пытается вызвать его методы.
Следующая диаграмма показывает архитектуру приложения RMI.
Давайте теперь обсудим компоненты этой архитектуры.
-
Транспортный уровень — этот уровень связывает клиента и сервер. Он управляет существующим соединением, а также устанавливает новые соединения.
-
Заглушка — заглушка — это представление (прокси) удаленного объекта на клиенте. Он находится в клиентской системе; он действует как шлюз для клиентской программы.
-
Скелет — это объект, который находится на стороне сервера. заглушка связывается с этим скелетом для передачи запроса удаленному объекту.
-
RRL (Remote Reference Layer) — это уровень, который управляет ссылками, сделанными клиентом на удаленный объект.
Транспортный уровень — этот уровень связывает клиента и сервер. Он управляет существующим соединением, а также устанавливает новые соединения.
Заглушка — заглушка — это представление (прокси) удаленного объекта на клиенте. Он находится в клиентской системе; он действует как шлюз для клиентской программы.
Скелет — это объект, который находится на стороне сервера. заглушка связывается с этим скелетом для передачи запроса удаленному объекту.
RRL (Remote Reference Layer) — это уровень, который управляет ссылками, сделанными клиентом на удаленный объект.
Работа приложения RMI
Следующие пункты суммируют, как работает приложение RMI —
-
Когда клиент выполняет вызов к удаленному объекту, он принимается заглушкой, которая в конечном итоге передает этот запрос в RRL.
-
Когда RRL на стороне клиента получает запрос, он вызывает метод invoke () объекта remoteRef . Он передает запрос в RRL на стороне сервера.
-
RRL на стороне сервера передает запрос в Skeleton (прокси-сервер на сервере), который, наконец, вызывает требуемый объект на сервере.
-
Результат передается обратно клиенту.
Когда клиент выполняет вызов к удаленному объекту, он принимается заглушкой, которая в конечном итоге передает этот запрос в RRL.
Когда RRL на стороне клиента получает запрос, он вызывает метод invoke () объекта remoteRef . Он передает запрос в RRL на стороне сервера.
RRL на стороне сервера передает запрос в Skeleton (прокси-сервер на сервере), который, наконец, вызывает требуемый объект на сервере.
Результат передается обратно клиенту.
Маршаллинг и демаршаллинг
Всякий раз, когда клиент вызывает метод, который принимает параметры на удаленном объекте, параметры объединяются в сообщение перед отправкой по сети. Эти параметры могут быть примитивного типа или объектов. В случае примитивного типа параметры объединяются и к нему прикрепляется заголовок. Если параметры являются объектами, они сериализуются. Этот процесс известен как сортировка .
На стороне сервера упакованные параметры разделяются, а затем вызывается требуемый метод. Этот процесс известен как демаршаллинг .
Реестр RMI
Реестр RMI — это пространство имен, в котором размещены все объекты сервера. Каждый раз, когда сервер создает объект, он регистрирует этот объект в RMIregistry (используя методы bind () или reBind () ). Они зарегистрированы с использованием уникального имени, известного как имя привязки .
Чтобы вызвать удаленный объект, клиенту нужна ссылка на этот объект. В это время клиент выбирает объект из реестра, используя его имя привязки (используя метод lookup () ).
Следующая иллюстрация объясняет весь процесс —
Цели РМИ
Ниже приведены цели RMI —
- Чтобы минимизировать сложность приложения.
- Чтобы сохранить безопасность типов.
- Распределенная сборка мусора.
- Минимизируйте разницу между работой с локальными и удаленными объектами.
Приложение Java RMI
Чтобы написать Java-приложение RMI, вам необходимо выполнить следующие шаги:
- Определите удаленный интерфейс
- Разработать класс реализации (удаленный объект)
- Разработать серверную программу
- Разработать клиентскую программу
- Скомпилируйте приложение
- Выполнить заявку
Определение удаленного интерфейса
Удаленный интерфейс предоставляет описание всех методов конкретного удаленного объекта. Клиент связывается с этим удаленным интерфейсом.
Чтобы создать удаленный интерфейс —
-
Создайте интерфейс, который расширяет предопределенный интерфейс Remote, который принадлежит пакету.
-
Объявите все бизнес-методы, которые могут быть вызваны клиентом в этом интерфейсе.
-
Поскольку существует вероятность возникновения проблем с сетью во время удаленных вызовов, может возникнуть исключение с именем RemoteException ; брось это.
Создайте интерфейс, который расширяет предопределенный интерфейс 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, созданный на предыдущем шаге, и предоставили тело для этого метода, который печатает сообщение.
// 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 .
Разработать серверную программу —
-
Создайте клиентский класс, из которого вы хотите вызвать удаленный объект.
-
Создайте удаленный объект , создав экземпляр класса реализации, как показано ниже.
-
Экспортируйте удаленный объект, используя метод exportObject () класса с именем UnicastRemoteObject, который принадлежит пакету java.rmi.server .
-
Получить реестр RMI с помощью метода getRegistry () класса LocateRegistry, который принадлежит пакету java.rmi.registry .
-
Свяжите удаленный объект, созданный с реестром, используя метод bind () класса Registry . В этот метод передайте строку, представляющую имя привязки и экспортируемый объект, в качестве параметров.
Создайте клиентский класс, из которого вы хотите вызвать удаленный объект.
Создайте удаленный объект , создав экземпляр класса реализации, как показано ниже.
Экспортируйте удаленный объект, используя метод 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 с помощью метода 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(); } } }
Компиляция приложения
Чтобы скомпилировать приложение —
- Скомпилируйте интерфейс Remote.
- Скомпилируйте класс реализации.
- Скомпилируйте серверную программу.
- Скомпилируйте клиентскую программу.
Или же,
Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.
Javac *.java
Выполнение заявки
Шаг 1 — Запустите реестр rmi, используя следующую команду.
start rmiregistry
Это запустит реестр rmi в отдельном окне, как показано ниже.
Шаг 2 — Запустите файл класса сервера, как показано ниже.
Java Server
Шаг 3 — Запустите файл класса клиента, как показано ниже.
java Client
Проверка — как только вы запустите клиент, вы увидите следующий вывод на сервере.
Java RMI — приложение с графическим интерфейсом
В предыдущей главе мы создали пример приложения 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.
Шаг 1 — Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.
Javac *.java
Шаг 2 — Запустите реестр rmi, используя следующую команду.
start rmiregistry
Это запустит реестр rmi в отдельном окне, как показано ниже.
Шаг 3 — Запустите файл класса сервера, как показано ниже.
Java Server
Шаг 4 — Запустите файл класса клиента, как показано ниже.
java Client
Проверка — как только вы запустите клиент, вы увидите следующий вывод на сервере.
Java RMI — Приложение базы данных
В предыдущей главе мы создали образец приложения RMI, в котором клиент вызывает метод, который отображает окно графического интерфейса пользователя (JavaFX).
В этой главе мы рассмотрим пример того, как клиентская программа может извлекать записи из таблицы в базе данных MySQL, находящейся на сервере.
Предположим, у нас есть таблица с именем student_data в деталях базы данных, как показано ниже.
+----+--------+--------+------------+---------------------+ | ID | NAME | BRANCH | PERCENTAGE | EMAIL | +----+--------+--------+------------+---------------------+ | 1 | Ram | IT | 85 | [email protected] | | 2 | Rahim | EEE | 95 | [email protected] | | 3 | Robert | ECE | 90 | [email protected] | +----+--------+--------+------------+---------------------+
Предположим, что имя пользователя myuser, а пароль — пароль .
Создание студенческого класса
Создайте класс Student с методами установки и получения, как показано ниже.
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; }
Разработка класса реализации
Создайте класс и реализуйте созданный выше интерфейс.
Здесь мы реализуем метод getStudents () интерфейса Remote . Когда вы вызываете этот метод, он получает записи таблицы с именем 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 .
Ниже приводится серверная программа этого приложения. Здесь мы расширим созданный выше класс, создадим удаленный объект и зарегистрируем его в реестре 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.
Шаг 1 — Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.
Javac *.java
Шаг 2 — Запустите реестр rmi, используя следующую команду.
start rmiregistry
Это запустит реестр rmi в отдельном окне, как показано ниже.
Шаг 3 — Запустите файл класса сервера, как показано ниже.
Java Server
Шаг 4 — Запустите файл класса клиента, как показано ниже.
java Client