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