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