Java RMI - Guide rapide

RMI signifie Remote Method Invocation. C'est un mécanisme qui permet à un objet résidant dans un système (JVM) d'accéder / d'appeler un objet s'exécutant sur une autre JVM.

RMI est utilisé pour créer des applications distribuées; il fournit une communication à distance entre les programmes Java. Il est fourni dans le packagejava.rmi.

Architecture d'une application RMI

Dans une application RMI, nous écrivons deux programmes, un server program (réside sur le serveur) et un client program (réside sur le client).

  • Dans le programme serveur, un objet distant est créé et la référence de cet objet est rendue disponible pour le client (en utilisant le registre).

  • Le programme client demande les objets distants sur le serveur et tente d'appeler ses méthodes.

Le schéma suivant montre l'architecture d'une application RMI.

Parlons maintenant des composants de cette architecture.

  • Transport Layer- Cette couche relie le client et le serveur. Il gère la connexion existante et établit également de nouvelles connexions.

  • Stub- Un stub est une représentation (proxy) de l'objet distant chez le client. Il réside dans le système client; il agit comme une passerelle pour le programme client.

  • Skeleton - C'est l'objet qui réside côté serveur. stub communique avec ce squelette pour transmettre la demande à l'objet distant.

  • RRL(Remote Reference Layer) - C'est la couche qui gère les références faites par le client à l'objet distant.

Fonctionnement d'une application RMI

Les points suivants résument le fonctionnement d'une application RMI -

  • Lorsque le client effectue un appel à l'objet distant, il est reçu par le stub qui transmet finalement cette demande au RRL.

  • Lorsque le RRL côté client reçoit la demande, il appelle une méthode appelée invoke() de l'objet remoteRef. Il transmet la demande au RRL côté serveur.

  • Le RRL côté serveur transmet la requête au Skeleton (proxy sur le serveur) qui appelle finalement l'objet requis sur le serveur.

  • Le résultat est renvoyé au client.

Marshalling et démarshalling

Chaque fois qu'un client appelle une méthode qui accepte des paramètres sur un objet distant, les paramètres sont regroupés dans un message avant d'être envoyés sur le réseau. Ces paramètres peuvent être de type primitif ou des objets. En cas de type primitif, les paramètres sont rassemblés et un en-tête y est attaché. Si les paramètres sont des objets, ils sont sérialisés. Ce processus est connu sous le nom demarshalling.

Du côté serveur, les paramètres compressés sont dégroupés, puis la méthode requise est appelée. Ce processus est connu sous le nom deunmarshalling.

Registre RMI

Le registre RMI est un espace de noms sur lequel tous les objets serveur sont placés. Chaque fois que le serveur crée un objet, il enregistre cet objet auprès de RMIregistry (en utilisantbind() ou reBind()méthodes). Ceux-ci sont enregistrés en utilisant un nom unique appelébind name.

Pour appeler un objet distant, le client a besoin d'une référence de cet objet. À ce moment-là, le client récupère l'objet du registre en utilisant son nom de liaison (en utilisantlookup() méthode).

L'illustration suivante explique l'ensemble du processus -

Objectifs du RMI

Voici les objectifs de RMI -

  • Pour minimiser la complexité de l'application.
  • Pour préserver la sécurité des types.
  • Collecte des déchets distribuée.
  • Minimisez la différence entre travailler avec des objets locaux et distants.

Pour écrire une application Java RMI, vous devez suivre les étapes ci-dessous -

  • Définir l'interface distante
  • Développer la classe d'implémentation (objet distant)
  • Développer le programme serveur
  • Développer le programme client
  • Compilez l'application
  • Exécutez l'application

Définition de l'interface distante

Une interface distante fournit la description de toutes les méthodes d'un objet distant particulier. Le client communique avec cette interface distante.

Pour créer une interface distante -

  • Créer une interface qui étend l'interface prédéfinie Remote qui appartient au package.

  • Déclarez toutes les méthodes métier pouvant être appelées par le client dans cette interface.

  • Puisqu'il y a un risque de problèmes de réseau pendant les appels à distance, une exception nommée RemoteExceptionpeut se produire; lancez-le.

Voici un exemple d'interface distante. Ici, nous avons défini une interface avec le nomHello et il a une méthode appelée printMsg().

import java.rmi.Remote; 
import java.rmi.RemoteException;  

// Creating Remote interface for our application 
public interface Hello extends Remote {  
   void printMsg() throws RemoteException;  
}

Développement de la classe d'implémentation (objet distant)

Nous devons implémenter l'interface distante créée à l'étape précédente. (Nous pouvons écrire une classe d'implémentation séparément ou nous pouvons directement faire en sorte que le programme serveur implémente cette interface.)

Pour développer une classe d'implémentation -

  • Implémentez l'interface créée à l'étape précédente.
  • Fournit une implémentation à toutes les méthodes abstraites de l'interface distante.

Voici une classe d'implémentation. Ici, nous avons créé une classe nomméeImplExample et implémenté l'interface Hello créé à l'étape précédente et fourni body pour cette méthode qui imprime un message.

// 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");  
   }  
}

Développement du programme serveur

Un programme serveur RMI doit implémenter l'interface distante ou étendre la classe d'implémentation. Ici, nous devons créer un objet distant et le lier auRMIregistry.

Pour développer un programme serveur -

  • Créez une classe client à partir de laquelle vous souhaitez appeler l'objet distant.

  • Create a remote object en instanciant la classe d'implémentation comme indiqué ci-dessous.

  • Exportez l'objet distant à l'aide de la méthode exportObject() de la classe nommée UnicastRemoteObject qui appartient au package java.rmi.server.

  • Obtenez le registre RMI en utilisant le getRegistry() méthode de la LocateRegistry classe qui appartient au package java.rmi.registry.

  • Liez l'objet distant créé au registre à l'aide du bind() méthode de la classe nommée Registry. À cette méthode, passez une chaîne représentant le nom de la liaison et l'objet exporté, en tant que paramètres.

Voici un exemple de programme serveur 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(); 
      } 
   } 
}

Développement du programme client

Écrivez un programme client dedans, récupérez l'objet distant et invoquez la méthode requise en utilisant cet objet.

Pour développer un programme client -

  • Créez une classe client à partir de laquelle vous souhaitez invoquer l'objet distant.

  • Obtenez le registre RMI en utilisant le getRegistry() méthode de la LocateRegistry classe qui appartient au package java.rmi.registry.

  • Récupérez l'objet du registre à l'aide de la méthode lookup() de la classe Registry qui appartient au package java.rmi.registry.

    Pour cette méthode, vous devez transmettre une valeur de chaîne représentant le nom de la liaison en tant que paramètre. Cela vous renverra l'objet distant.

  • La recherche () renvoie un objet de type remote, en le convertissant en type Hello.

  • Enfin, appelez la méthode requise à l'aide de l'objet distant obtenu.

Voici un exemple de programme client 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(); 
      } 
   } 
}

Compilation de l'application

Pour compiler l'application -

  • Compilez l'interface distante.
  • Compilez la classe d'implémentation.
  • Compilez le programme serveur.
  • Compilez le programme client.

Ou,

Ouvrez le dossier dans lequel vous avez stocké tous les programmes et compilez tous les fichiers Java comme indiqué ci-dessous.

Javac *.java

Exécution de l'application

Step 1 - Démarrez le rmi registre à l'aide de la commande suivante.

start rmiregistry

Cela va démarrer un rmi Registre sur une fenêtre distincte comme indiqué ci-dessous.

Step 2 - Exécutez le fichier de classe du serveur comme indiqué ci-dessous.

Java Server

Step 3 - Exécutez le fichier de classe client comme indiqué ci-dessous.

java Client

Verification - Dès que vous démarrez le client, vous verrez la sortie suivante sur le serveur.

Dans le chapitre précédent, nous avons créé un exemple d'application RMI. Dans ce chapitre, nous expliquerons comment créer une application RMI où un client appelle une méthode qui affiche une fenêtre GUI (JavaFX).

Définition de l'interface distante

Ici, nous définissons une interface distante nommée Hello avec une méthode nommée animation() dedans.

import java.rmi.Remote; 
import java.rmi.RemoteException;  

// Creating Remote interface for our application 
public interface Hello extends Remote { 
   void animation() throws RemoteException; 
}

Développement de la classe d'implémentation

Dans la classe d'implémentation (objet distant) de cette application, nous essayons de créer une fenêtre qui affiche le contenu de l'interface graphique, en utilisant 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();  
   }  
}

Programme serveur

Un programme serveur RMI doit implémenter l'interface distante ou étendre la classe d'implémentation. Ici, nous devons créer un objet distant et le lier auRMIregistry.

Voici le programme serveur de cette application. Ici, nous allons étendre la classe créée ci-dessus, créer un objet distant et l'enregistrer dans le registre RMI avec le nom de liaisonhello.

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(); 
      } 
   } 
}

Programme client

Voici le programme client de cette application. Ici, nous récupérons l'objet distant et invoquons sa méthode nomméeanimation().

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(); 
      } 
   } 
}

Étapes pour exécuter l'exemple

Voici les étapes pour exécuter notre exemple RMI.

Step 1 - Ouvrez le dossier dans lequel vous avez stocké tous les programmes et compilez tous les fichiers Java comme indiqué ci-dessous.

Javac *.java

Step 2 - Démarrez le rmi registre à l'aide de la commande suivante.

start rmiregistry

Cela va démarrer un rmi Registre sur une fenêtre distincte comme indiqué ci-dessous.

Step 3 - Exécutez le fichier de classe du serveur comme indiqué ci-dessous.

Java Server

Step 4 - Exécutez le fichier de classe client comme indiqué ci-dessous.

java Client

Verification - Dès que vous démarrez le client, vous verrez la sortie suivante sur le serveur.

Dans le chapitre précédent, nous avons créé un exemple d'application RMI dans laquelle un client appelle une méthode qui affiche une fenêtre GUI (JavaFX).

Dans ce chapitre, nous prendrons un exemple pour voir comment un programme client peut récupérer les enregistrements d'une table dans la base de données MySQL résidant sur le serveur.

Supposons que nous ayons une table nommée student_data dans la base de données details comme indiqué ci-dessous.

+----+--------+--------+------------+---------------------+ 
| ID | NAME   | BRANCH | PERCENTAGE | EMAIL               | 
+----+--------+--------+------------+---------------------+ 
|  1 | Ram    | IT     |         85 | [email protected]    | 
|  2 | Rahim  | EEE    |         95 | [email protected]  | 
|  3 | Robert | ECE    |         90 | [email protected] | 
+----+--------+--------+------------+---------------------+

Supposons que le nom de l'utilisateur est myuser et son mot de passe est password.

Créer une classe d'étudiants

Créer un Student classe avec setter et getter méthodes comme indiqué ci-dessous.

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; 
   } 
}

Définition de l'interface distante

Définissez l'interface distante. Ici, nous définissons une interface distante nomméeHello avec une méthode nommée getStudents ()dedans. Cette méthode retourne une liste qui contient l'objet de la classeStudent.

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;  
}

Développement de la classe d'implémentation

Créez une classe et implémentez ce qui a été créé ci-dessus interface.

Ici, nous mettons en œuvre le getStudents() méthode de la Remote interface. Lorsque vous appelez cette méthode, elle récupère les enregistrements d'une table nomméestudent_data. Définit ces valeurs sur la classe Student à l'aide de ses méthodes de définition, l'ajoute à un objet de liste et renvoie cette liste.

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;     
   }  
}

Programme serveur

Un programme serveur RMI doit implémenter l'interface distante ou étendre la classe d'implémentation. Ici, nous devons créer un objet distant et le lier auRMI registry.

Voici le programme serveur de cette application. Ici, nous allons étendre la classe créée ci-dessus, créer un objet distant et l'enregistrer dans le registre RMI avec le nom de liaisonhello.

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(); 
      } 
   } 
}

Programme client

Voici le programme client de cette application. Ici, nous récupérons l'objet distant et invoquons la méthode nomméegetStudents(). Il récupère les enregistrements de la table à partir de l'objet de liste et les affiche.

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(); 
      } 
   } 
}

Étapes pour exécuter l'exemple

Voici les étapes pour exécuter notre exemple RMI.

Step 1 - Ouvrez le dossier dans lequel vous avez stocké tous les programmes et compilez tous les fichiers Java comme indiqué ci-dessous.

Javac *.java

Step 2 - Démarrez le rmi registre à l'aide de la commande suivante.

start rmiregistry

Cela va démarrer un rmi Registre sur une fenêtre distincte comme indiqué ci-dessous.

Step 3 - Exécutez le fichier de classe du serveur comme indiqué ci-dessous.

Java Server

Step 4 - Exécutez le fichier de classe client comme indiqué ci-dessous.

java Client