John Squirrels
Livello 41
San Francisco

Java RMI

Pubblicato nel gruppo Random-IT
CIAO! Oggi considereremo un argomento piuttosto interessante: Java RMI. Questo è l'acronimo di Remote Method Invocation. È possibile utilizzare RMI per consentire a due programmi di comunicare tra loro, anche se si trovano su computer diversi. Suona bene? :) E non è così difficile da fare! Nella lezione di oggi analizzeremo gli elementi dell'interazione RMI e capiremo come configurarla. La prima cosa di cui abbiamo bisogno è un client e un server. Non abbiamo davvero bisogno di immergerci in profondità nella terminologia informatica. Quando si tratta di RMI, questi sono solo due programmi. Uno di questi includerà un oggetto e l'altro chiamerà metodi su quell'oggetto. Chiamare metodi di un oggetto che esiste in un programma diverso: questa è una cosa che non abbiamo ancora fatto! È ora di fare un tentativo! :) Per evitare di impantanarsi, facciamo Aiuta a mantenere semplice il nostro programma. In generale, un server esegue alcuni calcoli richiesti da un client. E così sarà con noi. Il nostro server sarà un semplice programma di calcolo. Avrà un solo metodo:moltiplicare() . Moltiplicherà due numeri inviati dal programma client e quindi restituirà il risultato. Prima di tutto, abbiamo bisogno di un'interfaccia:

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

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Perché abbiamo bisogno di un'interfaccia? Perché RMI si basa sulla creazione di proxy, che hai studiato nelle lezioni precedenti . Come probabilmente ricorderai, lavoriamo con i proxy tramite interfacce, non classi. Ci sono 2 requisiti importanti per la nostra interfaccia!
  1. Deve estendere l'interfaccia remota.
  2. Tutti i suoi metodi devono lanciare una RemoteException (l'IDE non lo farà automaticamente — devi aggiungerlo manualmente!).
Ora dobbiamo creare una classe server che implementi la nostra interfaccia Calcolatrice . RMI in pratica - 2Anche qui tutto è abbastanza semplice:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
Non c'è davvero nulla da commentare qui :) Ora dobbiamo scrivere un programma server che configurerà ed eseguirà il nostro oggetto calcolatrice. Sembrerà così:

import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
Scopriamolo :) Nella prima riga, dichiariamo una variabile String:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
Questa stringa è il nome univoco dell'oggetto remoto. Il nostro programma client utilizza questo nome per trovare il nostro server: lo vedrai in seguito. Successivamente, creiamo il nostro oggetto calcolatrice:

final RemoteCalculationServer server = new RemoteCalculationServer();
Qui è tutto chiaro. Quello che viene dopo è più interessante:

final Registry registry = LocateRegistry.createRegistry(2732);
Questo oggetto Registry è un registro di oggetti remoti. Questi sono oggetti a cui altri programmi possono accedere da remoto :) Abbiamo passato il numero 2732 al metodo LocateRegistry.createRegistry() . Questo è il numero di porta, un numero univoco che altri programmi useranno per trovare il nostro registro degli oggetti (di nuovo, lo vedrai sotto). Andando avanti... Vediamo cosa succede nella riga successiva:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
Creiamo uno stub in questa riga. Uno stub incapsula l'intera chiamata remota. Puoi considerare questo l'elemento più importante di RMI. Che cosa fa?
  1. Riceve tutte le informazioni su una chiamata remota di qualche metodo.
  2. Se il metodo ha parametri, lo stub li deserializzerà. Fai attenzione a questo punto! Gli argomenti che passi ai metodi chiamati in remoto devono essere serializzabili (dopo tutto, saranno trasmessi sulla rete). Questo non è un problema per noi, stiamo solo trasmettendo numeri. Ma se stai trasmettendo oggetti, non dimenticare questo requisito!
  3. Successivamente, lo stub chiama il metodo desiderato.
Passiamo il nostro oggetto server calcolatrice al metodo UnicastRemoteObject.exportObject() . Questo è il modo in cui rendiamo possibile chiamare in remoto i suoi metodi. Resta solo una cosa da fare:

registry.bind(UNIQUE_BINDING_NAME, stub);
"Registriamo" il nostro stub nel registro degli oggetti remoti con il nome che abbiamo creato all'inizio. Ora il cliente sarà in grado di trovarlo! Forse hai notato che abbiamo messo in stop il thread principale del programma alla fine:

Thread.sleep(Integer.MAX_VALUE);
Abbiamo solo bisogno che il server funzioni a lungo. Nell'IDE, lanceremo simultaneamente due metodi main() : primo, il metodo main() del server (nella classe ServerMain , che abbiamo già scritto), e secondo, il metodo main() del client (nella classe ClientMain , che scriveremo di seguito). È importante che il programma server non venga terminato mentre avviiamo il client, quindi lo mettiamo semplicemente in stop per molto tempo. In ogni caso, continuerà a funzionare :) Ora possiamo eseguire il metodo main() del nostro server . Lascialo funzionare e attendi che il programma client chiami qualche metodo :) Ora scriviamo il programma client! Invierà i numeri al nostro server per la moltiplicazione.

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
Sembra semplice. Ma cosa sta succedendo qui? Innanzitutto, il client deve conoscere il nome univoco dell'oggetto i cui metodi chiamerà in remoto. Di conseguenza, nel programma client, abbiamo creato la public static final String UNIQUE_BINDING_NAME = "server.calculator"; variabile. Successivamente, nel metodo main() , otteniamo l'accesso al registro degli oggetti remoti. Per fare ciò, dobbiamo chiamare il metodo LocateRegistry.getRegistry() e passare il numero di porta utilizzato per creare il nostro registro nel programma ServerMain (porta 2732; questo numero è solo un esempio — puoi provare a utilizzare un numero diverso):

final Registry registry = LocateRegistry.getRegistry(2732);
Ora dobbiamo solo ottenere l'oggetto desiderato dal registro! Questo è facile, perché conosciamo il suo nome univoco!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Prestare attenzione al casting del tipo. Trasmettiamo l'oggetto ricevuto all'interfaccia Calculator , non alla classe RemoteCalculationServer . Come abbiamo detto all'inizio della lezione, RMI si basa su un proxy, quindi le chiamate remote sono disponibili solo per i metodi di un'interfaccia, non per i metodi di una classe. Infine, chiamiamo in remoto il metodo multiply() sul nostro oggetto e inviamo il risultato alla console.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
Il metodo main() della classe ServerMain è già in esecuzione da molto tempo. Ora è il momento di eseguire il metodo main() nel programma client ( ClientMain )! Uscita console:

600
Questo è tutto! Il nostro programma (due programmi, in realtà!) ha fatto quello che doveva fare :) Se hai tempo e voglia, puoi ravvivarlo un po'. Ad esempio, fai in modo che la calcolatrice supporti le quattro operazioni aritmetiche standard e passa i numeri non come tipi primitivi, ma come oggetti CalculationInstance(int x, int y) . Ci vediamo alla prossima lezione! :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION