Java RMI - Guida rapida
RMI sta per Remote Method Invocation. È un meccanismo che consente a un oggetto che risiede in un sistema (JVM) di accedere / richiamare un oggetto in esecuzione su un'altra JVM.
RMI viene utilizzato per creare applicazioni distribuite; fornisce la comunicazione remota tra i programmi Java. Viene fornito nella confezionejava.rmi.
Architettura di un'applicazione RMI
In un'applicazione RMI, scriviamo due programmi, a server program (risiede sul server) e un file client program (risiede nel cliente).
All'interno del programma server, viene creato un oggetto remoto e il riferimento a tale oggetto viene reso disponibile per il client (utilizzando il registro).
Il programma client richiede gli oggetti remoti sul server e tenta di richiamare i suoi metodi.
Il diagramma seguente mostra l'architettura di un'applicazione RMI.
Parliamo ora dei componenti di questa architettura.
Transport Layer- Questo livello collega il client e il server. Gestisce la connessione esistente e crea anche nuove connessioni.
Stub- Uno stub è una rappresentazione (proxy) dell'oggetto remoto sul client. Risiede nel sistema client; funge da gateway per il programma client.
Skeleton - Questo è l'oggetto che risiede sul lato server. stub comunica con questo scheletro per passare la richiesta all'oggetto remoto.
RRL(Remote Reference Layer) - È il layer che gestisce i riferimenti fatti dal client all'oggetto remoto.
Lavorare su un'applicazione RMI
I seguenti punti riassumono il funzionamento di un'applicazione RMI:
Quando il client effettua una chiamata all'oggetto remoto, viene ricevuta dallo stub che alla fine passa questa richiesta all'RRL.
Quando l'RRL lato client riceve la richiesta, richiama un metodo chiamato invoke() dell'oggetto remoteRef. Passa la richiesta all'RRL sul lato server.
L'RRL sul lato server passa la richiesta allo Skeleton (proxy sul server) che infine richiama l'oggetto richiesto sul server.
Il risultato viene passato di nuovo al client.
Marshalling e Unmarshalling
Ogni volta che un client richiama un metodo che accetta parametri su un oggetto remoto, i parametri vengono raggruppati in un messaggio prima di essere inviati sulla rete. Questi parametri possono essere di tipo primitivo o oggetti. In caso di tipo primitivo, i parametri vengono messi insieme e ad esso viene allegata un'intestazione. Nel caso in cui i parametri siano oggetti, vengono serializzati. Questo processo è noto comemarshalling.
Sul lato server, i parametri compressi vengono disaggregati e quindi viene richiamato il metodo richiesto. Questo processo è noto comeunmarshalling.
Registro RMI
Il registro RMI è uno spazio dei nomi in cui vengono posizionati tutti gli oggetti del server. Ogni volta che il server crea un oggetto, registra questo oggetto con RMIregistry (utilizzandobind() o reBind()metodi). Questi vengono registrati utilizzando un nome univoco noto comebind name.
Per richiamare un oggetto remoto, il client necessita di un riferimento a tale oggetto. A quel punto, il client recupera l'oggetto dal registro utilizzando il suo nome di bind (utilizzandolookup() metodo).
La seguente illustrazione spiega l'intero processo:
Obiettivi di RMI
Di seguito sono riportati gli obiettivi di RMI:
- Per ridurre al minimo la complessità dell'applicazione.
- Per preservare l'indipendenza dai tipi.
- Garbage collection distribuita.
- Ridurre al minimo la differenza tra lavorare con oggetti locali e remoti.
Per scrivere un'applicazione Java RMI, è necessario seguire i passaggi indicati di seguito:
- Definisci l'interfaccia remota
- Sviluppa la classe di implementazione (oggetto remoto)
- Sviluppa il programma server
- Sviluppa il programma client
- Compilare l'applicazione
- Esegui l'applicazione
Definizione dell'interfaccia remota
Un'interfaccia remota fornisce la descrizione di tutti i metodi di un particolare oggetto remoto. Il client comunica con questa interfaccia remota.
Per creare un'interfaccia remota:
Crea un'interfaccia che estenda l'interfaccia predefinita Remote che appartiene al pacchetto.
Dichiarare tutti i metodi di business che possono essere richiamati dal client in questa interfaccia.
Poiché esiste la possibilità di problemi di rete durante le chiamate remote, un'eccezione denominata RemoteExceptionpotrebbe capitare; gettarlo.
Di seguito è riportato un esempio di un'interfaccia remota. Qui abbiamo definito un'interfaccia con il nomeHello e ha un metodo chiamato printMsg().
import java.rmi.Remote;
import java.rmi.RemoteException;
// Creating Remote interface for our application
public interface Hello extends Remote {
void printMsg() throws RemoteException;
}
Sviluppo della classe di implementazione (oggetto remoto)
Dobbiamo implementare l'interfaccia remota creata nel passaggio precedente. (Possiamo scrivere una classe di implementazione separatamente o possiamo fare in modo che il programma server implementi direttamente questa interfaccia.)
Per sviluppare una classe di implementazione -
- Implementa l'interfaccia creata nel passaggio precedente.
- Fornire implementazione a tutti i metodi astratti dell'interfaccia remota.
Di seguito è una classe di implementazione. Qui abbiamo creato una classe denominataImplExample e implementato l'interfaccia Hello creato nel passaggio precedente e fornito body per questo metodo che stampa un messaggio.
// 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");
}
}
Sviluppo del programma server
Un programma server RMI dovrebbe implementare l'interfaccia remota o estendere la classe di implementazione. Qui, dovremmo creare un oggetto remoto e associarlo al fileRMIregistry.
Per sviluppare un programma server:
Crea una classe client da cui desideri richiamare l'oggetto remoto.
Create a remote object istanziando la classe di implementazione come mostrato di seguito.
Esporta l'oggetto remoto utilizzando il metodo exportObject() della classe denominata UnicastRemoteObject che appartiene al pacchetto java.rmi.server.
Ottieni il registro RMI utilizzando il getRegistry() metodo del LocateRegistry classe che appartiene al pacchetto java.rmi.registry.
Associare l'oggetto remoto creato al registro utilizzando l'estensione bind() metodo della classe denominata Registry. A questo metodo, passare una stringa che rappresenta il nome del bind e l'oggetto esportato, come parametri.
Di seguito è riportato un esempio di un programma server 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();
}
}
}
Sviluppo del programma client
Scrivici un programma client, prendi l'oggetto remoto e invoca il metodo richiesto usando questo oggetto.
Per sviluppare un programma client -
Crea una classe client da cui intendi richiamare l'oggetto remoto.
Ottieni il registro RMI utilizzando il getRegistry() metodo del LocateRegistry classe che appartiene al pacchetto java.rmi.registry.
Recupera l'oggetto dal registro utilizzando il metodo lookup() della classe Registry che appartiene al pacchetto java.rmi.registry.
A questo metodo, è necessario passare un valore stringa che rappresenti il nome del bind come parametro. Questo ti restituirà l'oggetto remoto.
Lookup () restituisce un oggetto di tipo remote, eseguendo il down cast al tipo Hello.
Infine invoca il metodo richiesto utilizzando l'oggetto remoto ottenuto.
Di seguito è riportato un esempio di un programma 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();
}
}
}
Compilazione dell'applicazione
Per compilare l'applicazione:
- Compila l'interfaccia remota.
- Compila la classe di implementazione.
- Compila il programma del server.
- Compila il programma client.
O,
Apri la cartella in cui hai archiviato tutti i programmi e compila tutti i file Java come mostrato di seguito.
Javac *.java
Esecuzione dell'applicazione
Step 1 - Avvia il file rmi registro utilizzando il seguente comando.
start rmiregistry
Questo avvierà un file rmi registro su una finestra separata come mostrato di seguito.
Step 2 - Eseguire il file di classe del server come mostrato di seguito.
Java Server
Step 3 - Esegui il file della classe client come mostrato di seguito.
java Client
Verification - Non appena avvii il client, vedrai il seguente output nel server.
Nel capitolo precedente, abbiamo creato un'applicazione RMI di esempio. In questo capitolo, spiegheremo come creare un'applicazione RMI in cui un client richiama un metodo che visualizza una finestra GUI (JavaFX).
Definizione dell'interfaccia remota
Qui stiamo definendo un'interfaccia remota denominata Hello con un metodo denominato animation() dentro.
import java.rmi.Remote;
import java.rmi.RemoteException;
// Creating Remote interface for our application
public interface Hello extends Remote {
void animation() throws RemoteException;
}
Sviluppo della classe di implementazione
Nella classe Implementation (Remote Object) di questa applicazione, stiamo cercando di creare una finestra che visualizzi il contenuto della GUI, utilizzando 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();
}
}
Programma server
Un programma server RMI dovrebbe implementare l'interfaccia remota o estendere la classe di implementazione. Qui, dovremmo creare un oggetto remoto e associarlo al fileRMIregistry.
Di seguito è riportato il programma server di questa applicazione. Qui, estenderemo la classe creata sopra, creeremo un oggetto remoto e lo registreremo nel registro RMI con il nome di bindhello.
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();
}
}
}
Programma client
Di seguito è riportato il programma client di questa applicazione. Qui stiamo recuperando l'oggetto remoto e invocando il suo metodo denominatoanimation().
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();
}
}
}
Passaggi per eseguire l'esempio
Di seguito sono riportati i passaggi per eseguire il nostro esempio RMI.
Step 1 - Apri la cartella in cui hai memorizzato tutti i programmi e compila tutti i file Java come mostrato di seguito.
Javac *.java
Step 2 - Avvia il file rmi registro utilizzando il seguente comando.
start rmiregistry
Questo avvierà un file rmi registro su una finestra separata come mostrato di seguito.
Step 3 - Eseguire il file di classe del server come mostrato di seguito.
Java Server
Step 4 - Esegui il file della classe client come mostrato di seguito.
java Client
Verification - Non appena avvii il client, vedrai il seguente output nel server.
Nel capitolo precedente, abbiamo creato un'applicazione RMI di esempio in cui un client richiama un metodo che visualizza una finestra GUI (JavaFX).
In questo capitolo, faremo un esempio per vedere come un programma client può recuperare i record di una tabella nel database MySQL che risiede sul server.
Supponiamo di avere una tabella denominata student_data nel database details come mostrato di seguito.
+----+--------+--------+------------+---------------------+
| ID | NAME | BRANCH | PERCENTAGE | EMAIL |
+----+--------+--------+------------+---------------------+
| 1 | Ram | IT | 85 | [email protected] |
| 2 | Rahim | EEE | 95 | [email protected] |
| 3 | Robert | ECE | 90 | [email protected] |
+----+--------+--------+------------+---------------------+
Supponiamo che il nome dell'utente sia myuser e la sua password è password.
Creazione di una classe per studenti
Creare un Student classe con setter e getter metodi come mostrato di seguito.
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;
}
}
Definizione dell'interfaccia remota
Definisci l'interfaccia remota. Qui stiamo definendo un'interfaccia remota denominataHello con un metodo denominato getStudents ()dentro. Questo metodo restituisce una lista che contiene l'oggetto della 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;
}
Sviluppo della classe di implementazione
Crea una classe e implementa quanto sopra creato interface.
Qui stiamo implementando il getStudents() metodo del Remote interface. Quando si richiama questo metodo, vengono recuperati i record di una tabella denominatastudent_data. Imposta questi valori alla classe Student utilizzando i suoi metodi setter, lo aggiunge a un oggetto elenco e restituisce tale elenco.
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;
}
}
Programma server
Un programma server RMI dovrebbe implementare l'interfaccia remota o estendere la classe di implementazione. Qui, dovremmo creare un oggetto remoto e associarlo al fileRMI registry.
Di seguito è riportato il programma server di questa applicazione. Qui, estenderemo la classe creata sopra, creeremo un oggetto remoto e lo registreremo nel registro RMI con il nome di bindhello.
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();
}
}
}
Programma client
Di seguito è riportato il programma client di questa applicazione. Qui stiamo recuperando l'oggetto remoto e invocando il metodo denominatogetStudents(). Recupera i record della tabella dall'oggetto elenco e li visualizza.
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();
}
}
}
Passaggi per eseguire l'esempio
Di seguito sono riportati i passaggi per eseguire il nostro esempio RMI.
Step 1 - Apri la cartella in cui hai memorizzato tutti i programmi e compila tutti i file Java come mostrato di seguito.
Javac *.java
Step 2 - Avvia il file rmi registro utilizzando il seguente comando.
start rmiregistry
Questo avvierà un file rmi registro su una finestra separata come mostrato di seguito.
Step 3 - Eseguire il file di classe del server come mostrato di seguito.
Java Server
Step 4 - Esegui il file della classe client come mostrato di seguito.
java Client