RMI de Java - Guía rápida
RMI significa Remote Method Invocation. Es un mecanismo que permite que un objeto que reside en un sistema (JVM) acceda / invoque un objeto que se ejecuta en otra JVM.
RMI se utiliza para crear aplicaciones distribuidas; proporciona comunicación remota entre programas Java. Se proporciona en el paquete.java.rmi.
Arquitectura de una aplicación RMI
En una aplicación RMI, escribimos dos programas, un server program (reside en el servidor) y un client program (reside en el cliente).
Dentro del programa del servidor, se crea un objeto remoto y la referencia de ese objeto está disponible para el cliente (usando el registro).
El programa cliente solicita los objetos remotos en el servidor e intenta invocar sus métodos.
El siguiente diagrama muestra la arquitectura de una aplicación RMI.
Analicemos ahora los componentes de esta arquitectura.
Transport Layer- Esta capa conecta al cliente y al servidor. Gestiona la conexión existente y también establece nuevas conexiones.
Stub- Un stub es una representación (proxy) del objeto remoto en el cliente. Reside en el sistema del cliente; actúa como puerta de enlace para el programa cliente.
Skeleton - Este es el objeto que reside en el lado del servidor. stub se comunica con este esqueleto para pasar la solicitud al objeto remoto.
RRL(Remote Reference Layer) - Es la capa que gestiona las referencias que hace el cliente al objeto remoto.
Funcionamiento de una aplicación RMI
Los siguientes puntos resumen cómo funciona una aplicación RMI:
Cuando el cliente realiza una llamada al objeto remoto, el stub lo recibe y finalmente pasa esta solicitud al RRL.
Cuando el RRL del lado del cliente recibe la solicitud, invoca un método llamado invoke() del objeto remoteRef. Pasa la solicitud al RRL en el lado del servidor.
El RRL en el lado del servidor pasa la solicitud al Skeleton (proxy en el servidor) que finalmente invoca el objeto requerido en el servidor.
El resultado se devuelve al cliente.
Marshalling y Unmarshalling
Siempre que un cliente invoca un método que acepta parámetros en un objeto remoto, los parámetros se agrupan en un mensaje antes de enviarse a través de la red. Estos parámetros pueden ser de tipo primitivo u objetos. En el caso del tipo primitivo, los parámetros se juntan y se le adjunta un encabezado. En caso de que los parámetros sean objetos, entonces se serializan. Este proceso se conoce comomarshalling.
En el lado del servidor, los parámetros empaquetados se desagregan y luego se invoca el método requerido. Este proceso se conoce comounmarshalling.
Registro RMI
El registro RMI es un espacio de nombres en el que se colocan todos los objetos del servidor. Cada vez que el servidor crea un objeto, registra este objeto con el registro RMI (usandobind() o reBind()métodos). Estos se registran con un nombre único conocido comobind name.
Para invocar un objeto remoto, el cliente necesita una referencia de ese objeto. En ese momento, el cliente obtiene el objeto del registro usando su nombre de enlace (usandolookup() método).
La siguiente ilustración explica todo el proceso:
Objetivos de RMI
Los siguientes son los objetivos de RMI:
- Minimizar la complejidad de la aplicación.
- Para preservar la seguridad del tipo.
- Recolección de basura distribuida.
- Minimice la diferencia entre trabajar con objetos locales y remotos.
Para escribir una aplicación RMI Java, deberá seguir los pasos que se indican a continuación:
- Definir la interfaz remota
- Desarrollar la clase de implementación (objeto remoto)
- Desarrollar el programa del servidor
- Desarrollar el programa del cliente
- Compila la aplicación
- Ejecuta la aplicación
Definición de la interfaz remota
Una interfaz remota proporciona la descripción de todos los métodos de un objeto remoto en particular. El cliente se comunica con esta interfaz remota.
Para crear una interfaz remota:
Cree una interfaz que amplíe la interfaz predefinida Remote que pertenece al paquete.
Declare todos los métodos comerciales que el cliente puede invocar en esta interfaz.
Dado que existe la posibilidad de problemas de red durante las llamadas remotas, una excepción denominada RemoteExceptionpuede ocurrir; tírarlo.
A continuación se muestra un ejemplo de una interfaz remota. Aquí hemos definido una interfaz con el nombreHello y tiene un método llamado printMsg().
import java.rmi.Remote;
import java.rmi.RemoteException;
// Creating Remote interface for our application
public interface Hello extends Remote {
void printMsg() throws RemoteException;
}
Desarrollo de la clase de implementación (objeto remoto)
Necesitamos implementar la interfaz remota creada en el paso anterior. (Podemos escribir una clase de implementación por separado o podemos hacer que el programa del servidor implemente esta interfaz directamente).
Para desarrollar una clase de implementación:
- Implemente la interfaz creada en el paso anterior.
- Proporcionar implementación a todos los métodos abstractos de la interfaz remota.
A continuación se muestra una clase de implementación. Aquí, hemos creado una clase llamadaImplExample e implementé la interfaz Hello creado en el paso anterior y proporcionado body para este método que imprime un mensaje.
// 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");
}
}
Desarrollar el programa de servidor
Un programa de servidor RMI debe implementar la interfaz remota o extender la clase de implementación. Aquí, deberíamos crear un objeto remoto y vincularlo alRMIregistry.
Para desarrollar un programa de servidor:
Cree una clase de cliente desde donde desee invocar el objeto remoto.
Create a remote object instanciando la clase de implementación como se muestra a continuación.
Exportar el objeto remoto usando el método exportObject() de la clase nombrada UnicastRemoteObject que pertenece al paquete java.rmi.server.
Obtenga el registro RMI usando el getRegistry() método del LocateRegistry clase que pertenece al paquete java.rmi.registry.
Vincular el objeto remoto creado al registro usando el bind() método de la clase llamada Registry. Para este método, pase una cadena que represente el nombre de enlace y el objeto exportado, como parámetros.
A continuación se muestra un ejemplo de un programa de servidor 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();
}
}
}
Desarrollar el programa del cliente
Escriba un programa cliente en él, recupere el objeto remoto e invoque el método requerido usando este objeto.
Para desarrollar un programa de cliente:
Crea una clase de cliente desde donde pretendes invocar el objeto remoto.
Obtenga el registro RMI usando el getRegistry() método del LocateRegistry clase que pertenece al paquete java.rmi.registry.
Obtener el objeto del registro usando el método lookup() de la clase Registry que pertenece al paquete java.rmi.registry.
Para este método, debe pasar un valor de cadena que represente el nombre de enlace como parámetro. Esto le devolverá el objeto remoto.
El lookup () devuelve un objeto de tipo remoto, lo convierte al tipo Hello.
Finalmente, invoque el método requerido utilizando el objeto remoto obtenido.
A continuación se muestra un ejemplo de un programa de cliente 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();
}
}
}
Compilar la aplicación
Para compilar la aplicación:
- Compile la interfaz remota.
- Compile la clase de implementación.
- Compile el programa del servidor.
- Compile el programa cliente.
O,
Abra la carpeta donde ha almacenado todos los programas y compile todos los archivos Java como se muestra a continuación.
Javac *.java
Ejecución de la aplicación
Step 1 - Inicie el rmi registro usando el siguiente comando.
start rmiregistry
Esto iniciará un rmi registro en una ventana separada como se muestra a continuación.
Step 2 - Ejecute el archivo de clase del servidor como se muestra a continuación.
Java Server
Step 3 - Ejecute el archivo de clase de cliente como se muestra a continuación.
java Client
Verification - Tan pronto como inicie el cliente, verá el siguiente resultado en el servidor.
En el capítulo anterior, creamos una aplicación RMI de muestra. En este capítulo, explicaremos cómo crear una aplicación RMI donde un cliente invoca un método que muestra una ventana GUI (JavaFX).
Definición de la interfaz remota
Aquí, estamos definiendo una interfaz remota llamada Hello con un método llamado animation() en eso.
import java.rmi.Remote;
import java.rmi.RemoteException;
// Creating Remote interface for our application
public interface Hello extends Remote {
void animation() throws RemoteException;
}
Desarrollar la clase de implementación
En la clase de implementación (objeto remoto) de esta aplicación, estamos intentando crear una ventana que muestre el contenido de la GUI, utilizando 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();
}
}
Programa de servidor
Un programa de servidor RMI debe implementar la interfaz remota o extender la clase de implementación. Aquí, deberíamos crear un objeto remoto y vincularlo alRMIregistry.
A continuación se muestra el programa de servidor de esta aplicación. Aquí, ampliaremos la clase creada anteriormente, crearemos un objeto remoto y lo registraremos en el registro RMI con el nombre de enlace.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();
}
}
}
Programa de cliente
A continuación se muestra el programa cliente de esta aplicación. Aquí, buscamos el objeto remoto e invocamos su método llamadoanimation().
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();
}
}
}
Pasos para ejecutar el ejemplo
Los siguientes son los pasos para ejecutar nuestro ejemplo RMI.
Step 1 - Abra la carpeta donde ha almacenado todos los programas y compile todos los archivos Java como se muestra a continuación.
Javac *.java
Step 2 - Inicie el rmi registro usando el siguiente comando.
start rmiregistry
Esto iniciará un rmi registro en una ventana separada como se muestra a continuación.
Step 3 - Ejecute el archivo de clase del servidor como se muestra a continuación.
Java Server
Step 4 - Ejecute el archivo de clase de cliente como se muestra a continuación.
java Client
Verification - Tan pronto como inicie el cliente, verá el siguiente resultado en el servidor.
En el capítulo anterior, creamos una aplicación RMI de muestra donde un cliente invoca un método que muestra una ventana GUI (JavaFX).
En este capítulo, tomaremos un ejemplo para ver cómo un programa cliente puede recuperar los registros de una tabla en la base de datos MySQL que reside en el servidor.
Supongamos que tenemos una tabla llamada student_data en la base de datos details Como se muestra abajo.
+----+--------+--------+------------+---------------------+
| ID | NAME | BRANCH | PERCENTAGE | EMAIL |
+----+--------+--------+------------+---------------------+
| 1 | Ram | IT | 85 | [email protected] |
| 2 | Rahim | EEE | 95 | [email protected] |
| 3 | Robert | ECE | 90 | [email protected] |
+----+--------+--------+------------+---------------------+
Suponga que el nombre del usuario es myuser y su contraseña es password.
Crear una clase para estudiantes
Crear un Student clase con setter y getter métodos como se muestra a continuación.
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;
}
}
Definición de la interfaz remota
Defina la interfaz remota. Aquí, estamos definiendo una interfaz remota llamadaHello con un método llamado getStudents ()en eso. Este método devuelve una lista que contiene el objeto de la clase.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;
}
Desarrollar la clase de implementación
Cree una clase e implemente lo creado anteriormente interface.
Aquí estamos implementando el getStudents() método del Remote interface. Cuando invoca este método, recupera los registros de una tabla llamadastudent_data. Establece estos valores en la clase Student usando sus métodos de establecimiento, los agrega a un objeto de lista y devuelve esa lista.
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;
}
}
Programa de servidor
Un programa de servidor RMI debe implementar la interfaz remota o extender la clase de implementación. Aquí, deberíamos crear un objeto remoto y vincularlo alRMI registry.
A continuación se muestra el programa de servidor de esta aplicación. Aquí, ampliaremos la clase creada anteriormente, crearemos un objeto remoto y lo registraremos en el registro RMI con el nombre de enlace.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();
}
}
}
Programa de cliente
A continuación se muestra el programa cliente de esta aplicación. Aquí, buscamos el objeto remoto e invocamos el método llamadogetStudents(). Recupera los registros de la tabla del objeto de lista y los muestra.
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();
}
}
}
Pasos para ejecutar el ejemplo
Los siguientes son los pasos para ejecutar nuestro ejemplo RMI.
Step 1 - Abra la carpeta donde ha almacenado todos los programas y compile todos los archivos Java como se muestra a continuación.
Javac *.java
Step 2 - Inicie el rmi registro usando el siguiente comando.
start rmiregistry
Esto iniciará un rmi registro en una ventana separada como se muestra a continuación.
Step 3 - Ejecute el archivo de clase del servidor como se muestra a continuación.
Java Server
Step 4 - Ejecute el archivo de clase de cliente como se muestra a continuación.
java Client