Invocazione del metodo remoto Java
RMI ( Java Remote Method Invocation ) è un meccanismo offerto da Java per invocare un metodo in remoto. Fa parte dell'ambiente runtime Java standard e fornisce un semplice meccanismo per la comunicazione con il server nelle applicazioni distribuite solo Java. Se è richiesta la comunicazione tra altre tecnologie, è necessario utilizzare CORBA o SOAP anziché RMI.
RMI si caratterizza per la sua facilità d'uso nella programmazione in quanto è specificamente progettato per Java; fornisce il passaggio di oggetti per riferimento (non consentito da SOAP), la Garbage Collection distribuita (Distributed Garbage Collector) e il passaggio di tipo arbitrario (funzionalità non fornita da CORBA).
Tramite RMI, un programma Java può esportare un oggetto , rendendo l'oggetto accessibile in rete e il programma in attesa di richieste su una porta TCP . Successivamente, un client può connettersi e invocare i metodi forniti dall'oggetto.
L'invocazione consiste nei seguenti passaggi:
- Marshalling dei parametri (usando la funzionalità di serializzazione di Java ).
- Invocazione del metodo (del client sul server). Il chiamante attende una risposta.
- Al termine dell'esecuzione, il server serializza il valore restituito (se presente) e lo invia al client.
- Il codice client riceve la risposta e continua come se la chiamata fosse stata locale.
Contesto
Dalla versione 1.1 di JDK, Java ha il proprio ORB : RMI (Remote Method Invocation). Sebbene RMI sia un ORB in senso generale, non è un modello conforme a CORBA. RMI è nativo di Java, ovvero è un'estensione del linguaggio principale. RMI si basa interamente sul nucleo della serializzazione degli oggetti Java, nonché sull'implementazione sia della portabilità che dei meccanismi per caricare e scaricare oggetti su altri sistemi, ecc.
L'uso di RMI è molto naturale per qualsiasi programmatore Java poiché non deve imparare una nuova tecnologia completamente diversa da quella con cui svilupperà. Tuttavia, RMI presenta alcune limitazioni dovute alla sua stretta integrazione con Java, la principale è che questa tecnologia non consente l'interazione con applicazioni scritte in un altro linguaggio.
RMI, come estensione di Java, è una tecnologia di programmazione progettata per risolvere problemi scrivendo e organizzando codice eseguibile. Pertanto RMI costituisce un punto specifico nello spazio delle tecnologie di programmazione insieme a C, C++, Smalltalk, ecc.
La principale differenza tra l'utilizzo di RPC e RMI è che RMI è un meccanismo per l'invocazione di procedure remote basato sul linguaggio di programmazione Java che supporta l'interazione tra oggetti, mentre RPC non supporta questa funzione.
Architettura
L'architettura RMI può essere vista come un modello a quattro livelli.
Primo strato
Il primo livello è il livello dell'applicazione e corrisponde all'effettiva implementazione delle applicazioni client e server. Qui si svolgono chiamate di alto livello per accedere ed esportare oggetti remoti. Qualsiasi applicazione che desideri che i propri metodi siano disponibili per l'accesso da parte di client remoti deve dichiarare tali metodi in un'interfaccia che estenda java.rmi.Remote. Tale interfaccia viene fondamentalmente utilizzata per "contrassegnare" un oggetto come accessibile in remoto. Una volta implementati i metodi, l'oggetto deve essere esportato. Questo può essere fatto implicitamente se l'oggetto estende la classe UnicastRemoteObject (pacchetto java.rmi.server), oppure può essere fatto esplicitamente chiamando il metodo exportObject() dello stesso pacchetto.
Secondo strato
Il livello 2 è il livello proxy, o livello dello scheletro stub. Questo livello è quello che interagisce direttamente con il livello dell'applicazione. Tutte le chiamate a oggetti e azioni remoti insieme ai relativi parametri e oggetti restituiti avvengono in questo livello.
Terzo strato
Il livello 3 è il livello di riferimento remoto ed è responsabile della gestione della parte semantica delle invocazioni remote. È anche responsabile della gestione della replica degli oggetti e dell'esecuzione di attività specifiche per l'implementazione con oggetti remoti, come stabilire la persistenza semantica e strategie adeguate per il ripristino da connessioni perse. In questo livello, è prevista una connessione orientata al flusso dal livello di trasporto.
Quarto strato
Lo strato 4 è lo strato di trasporto. È responsabile della realizzazione dei collegamenti necessari e della gestione del trasporto dei dati da una macchina all'altra. Il protocollo di trasporto sottostante per RMI è Java Remote Method Protocol (JRMP), che è "compreso" solo dai programmi Java.
Elementi
Ogni applicazione RMI è normalmente suddivisa in 2 parti:
- Un server, che crea alcuni oggetti remoti, crea riferimenti per renderli accessibili e attende che il client li invochi.
- Un client, che ottiene un riferimento a oggetti remoti sul server e li richiama.
Esempio
Un server RMI consiste nella definizione di un oggetto remoto che verrà utilizzato dai client. Per creare un oggetto remoto, viene definita un'interfaccia e l'oggetto remoto sarà una classe che implementa tale interfaccia. Vediamo come creare un server di esempio in 3 passaggi:
- Definire l'interfaccia remota. Quando viene creata un'interfaccia remota:
- L'interfaccia deve essere pubblica.
- Deve ereditare dall'interfaccia java.rmi.Remote, per indicare che può essere chiamato da qualsiasi macchina virtuale Java.
- Ogni metodo remoto deve generare l'eccezione java.rmi.RemoteException nella sua clausola throws, oltre a tutte le eccezioni che può gestire.
interfaccia pubblica MyRemoteInterface estende java . mi . Remote
{
public void myMethod1 () lancia java . mi . RemoteException ;
public int myMethod2 () lancia java . mi . RemoteException ;
}
- Implementare l'interfaccia remota
la classe pubblica MyRemoteClass
estende java . mi . server . UnicastRemoteObject
implementa MyRemoteInterface
{
public MyRemoteClass () lancia java . mi . RemoteException
{
super (); //Chiama il costruttore della classe base (UnicastRemoteObject)
// Codice costruttore
}
public void myMethod1 () lancia java . mi . RemoteException
{
// Qui mettiamo il codice che vogliamo
System . fuori . println ( "Sono in myMethod1()" );
}
public int myMethod2 () lancia java . mi . RemoteException
{
ritorno 5 ; // Qui mettiamo il codice che vogliamo
}
public void otherMethod ()
{
// Se definiamo un altro metodo, non potrebbe essere chiamato
// da remoto in quanto non proviene dall'interfaccia remota
}
public static void main ( String [] args )
{
try
{
MyRemoteInterface mir = new MyRemoteClass ();
java . mi . Denominazione . rebind ( "rmi://" + java .net . InetAddress . getLocalHost (). getHostAddress ( ) + ":" + args [ 0 ] + "/TestRMI" , mir ); } catch ( Eccezione e ) { e . printStackTrace (); } } }
- Come puoi vedere, la classe MyRemoteClass implementa l'interfaccia MyRemoteInterface che abbiamo precedentemente definito. Inoltre, eredita da UnicastRemoteObject, che è una classe Java che possiamo usare come superclasse per implementare oggetti remoti.
- Quindi, all'interno della classe, definiamo un costruttore (che genera l'eccezione RemoteException perché generata anche dalla superclasse UnicastRemoteObject) e i metodi delle interfacce che implementa.
- Infine, nel metodo main, definiamo il codice per creare l'oggetto remoto che vogliamo condividere e rendere visibile l'oggetto remoto ai client, usando la classe Naming e il suo metodo rebind(...).
Nota: per comodità, abbiamo inserito il metodo main() all'interno della stessa classe. È possibile definire una classe separata responsabile della registrazione dell'oggetto remoto.
- Compila ed esegui il server
Abbiamo già definito il server. Ora dobbiamo compilare le tue classi usando i seguenti passaggi:
- Compiliamo l'interfaccia remota. Inoltre lo raggruppiamo in un file JAR per mantenerlo presente sia sul client che sul server:
javac MyRemoteInterface.java jar cvf objRemotes.jar MyRemoteInterface.class
- Successivamente, compiliamo le classi che implementano le interfacce. E per ognuno di essi generiamo i file Stub e Skeleton per mantenere il riferimento all'oggetto remoto, utilizzando il comando rmic:
set CLASSPATH=%CLASSPATH%;.\Remoteobj.jar;. javac MyRemoteClass.java rmic -d. MyRemoteClass
Possiamo vedere nella nostra directory di lavoro che sono stati generati automaticamente due file .class (MiClaseRemota_Skel.class e MiClaseRemota_Stub.class) corrispondenti al livello stub-skeleton dell'architettura RMI.
- Per eseguire il server, seguiamo questi passaggi:
- La registrazione RMI viene avviata per consentire la registrazione e la ricerca di oggetti remoti. Il registro si occupa di gestire un insieme di oggetti remoti da condividere e di cercarli quando richiesto dai client. Funziona con l'applicazione rmiregistry distribuita con Java, a cui possiamo opzionalmente passare la porta per la connessione (per impostazione predefinita, 1099).
Nel caso di Windows, deve essere eseguito:
avviare rmiregistro 1234
E nel caso di Linux:
registro e
- Infine, viene avviato il server:
java -Djava.rmi.server.hostname=127.0.0.1 MyRemoteClass 1234
- Crea un client RMI
Definiremo ora un client che accederà agli oggetti remoti che creiamo. Per questo seguiamo i seguenti passaggi:
- Definisci la classe per ottenere gli oggetti remoti richiesti
La seguente classe ottiene un oggetto di tipo MyRemoteInterface, implementato sul nostro server:
classe pubblica MyRMIClient
{
client MyRMIC privato (){};
public static void main ( String [] args )
{
try
{
MyRemoteInterface mir = ( MyRemoteInterface ) java . mi . Denominazione . ricerca ( "rmi://" +
args [ 0 ] + ":" + args [ 1 ] + "/RMITest" );
// Stampa myMethod1() tante volte quante myMethod2() restituisce
per ( int i = 1 ; i <= myr . myMethod2 (); i ++ )
myr . mioMetodo1 ();
}
catch ( Eccezione e )
{
e . printStackTrace ();
}
}
}
Come puoi vedere, consiste semplicemente nel cercare l'oggetto remoto nel registro RMI della macchina remota. Per fare ciò utilizziamo la classe Naming e il suo metodo lookup(...).
- Compila ed esegui il client
Una volta che abbiamo già definito il client, per compilarlo facciamo:
set CLASSPATH=%CLASSPATH%;.\Remoteobj.jar;. javac MyRMIClient.java
Quindi, per eseguire il client, eseguiamo:
java MyClientRMI 127.0.0.1 1234
Il file stub della classe remota deve essere accessibile. Per fare ciò, lo copiamo sul client e lo includiamo nel suo CLASSPATH, oppure lo rimuoviamo dal CLASSPATH del server e includiamo il suo percorso nel java.rmi.codebase del server (se non viene rimosso dal CLASSPATH del server, l'opzione java. rmi.codebase, e il client non potrà accedere allo Stub).Se diamo un'occhiata alla finestra in cui è in esecuzione il server RMI, vedremo come è stato trovato l'oggetto remoto e come sono stati eseguiti i suoi metodi:
Vedi anche
Collegamenti esterni
- Esempio RMI semplice
- Tutorial Java RMI Tutorial di Sun Microsystems (in inglese)
- Percorso: RMI Java Documentazione ufficiale RMI
- Una panoramica delle applicazioni RMI Introduzione ufficiale alle applicazioni Java RMI