RMI ( eng. Remote Method Invocation ) är ett programmeringsgränssnitt för anrop av fjärrmetoder på Java-språket .
En distribuerad objektmodell som specificerar hur fjärrmetoder anropas när de körs på en annan virtuell Java-maskin .
När du kommer åt ett objekt på en annan dator är det möjligt att anropa metoder på det objektet. Du behöver bara skicka metodparametrarna till en annan maskin, berätta för objektet att köra metoden och sedan få tillbaka returvärdet. RMI-mekanismen gör det möjligt att organisera utförandet av alla dessa operationer.
I RMI-termer kallas objektet som anropar fjärrmetoden klientobjektet , och fjärrobjektet kallas serverobjektet . Datorer fungerar som klient och server endast för ett specifikt samtal. Det är möjligt att under nästa operation kommer dessa datorer att byta roller, det vill säga att servern för det föregående anropet kan själv bli en klient när den kommer åt ett objekt på en annan dator.
När du anropar en metod på ett fjärrobjekt anropar den faktiskt en vanlig Java-språkmetod inkapslad i ett speciellt stubobjekt som är en representant för serverobjektet. Stubben finns på klientdatorn, inte på servern. Den packar parametrarna för fjärrmetoden i ett block med byte . Varje parameter kodas med en algoritm som ger hårdvaruoberoende. Till exempel sänds siffror alltid i den ordning som den mest signifikanta byten (big-endian) sänds först. I det här fallet serialiseras objekten . Processen för parameterkodning kallas parameterrangering . Huvudsyftet med att distribuera parametrar är att konvertera dem till ett format som är lämpligt för att överföra parametrar från en virtuell maskin till en annan.
Stubmetoden skapar ett block som innehåller följande element:
Stubmetoden skickar sedan denna information till servern. Därefter gör mottagarobjektet, skelettet, följande för varje fjärrmetodanrop:
Klientstubobjektet lindar returvärdet eller undantaget som tas emot från servern. Resultatet av vikningen blir returvärdet för stubbmetoden. Om fjärrmetoden returnerar ett undantag kommer stubobjektet att försöka igen i klientobjektets miljö.
Att anropa en fjärrmetod använder samma syntax som att anropa en lokal metod . Till exempel, för att anropa metoden för det centralagetQuantity() Warehouse-stubobjektet på en fjärrdator, skulle du använda följande kod.
int q = centralWarehouse . getQuantity ( "SuperSucker 100 Dammsugare" );För att komma åt fjärrmetoder använder klientkoden alltid objektvariabler av typen gränssnitt. Till exempel kan följande gränssnitt vara associerat med metoden ovan:
gränssnitt Warehouse { int getQuantity ( String description ) throws RemoteException ; Produkt getProduct ( kund kund ) kastar RemoteException ; // ... }En variabeldeklaration för ett objekt som implementerar detta gränssnitt skulle se ut så här:
LagercentralWarehouse = // ... ;Naturligtvis är gränssnitt abstraktioner och innehåller bara en lista över metoder. Variabler av typen gränssnitt måste alltid associeras med ett faktiskt objekt. När man anropar fjärrobjekt hänvisar variabeln till stubbobjektet. I det här fallet vet inte klientprogrammet något om typen av stubb, och själva stubbarna och deras tillhörande objekt skapas automatiskt.
När du skickar ett objekt till ett annat program (det kan vara en parameter eller ett returvärde för en fjärrmetod) behöver du en klassfil som motsvarar detta objekt. Till exempel en metod som returnerar ett värde av typen Produkt. Vid kompilering av klientprogrammet måste klassfilen Product.class genereras.
När du laddar ner kodsnuttar över nätverket finns det alltid tvivel om korrekt säkerhet. Som ett resultat använder applikationer som använder RMI en säkerhetshanterare . Det skyddar pluggarna från att virus tränger in i dem.
KlassRmiServer - håller reda på RMI-förfrågningar och implementerar gränssnittet som används av klienten för att anropa fjärrmetoder.
importera java.rmi.Naming ; importera java.rmi.RemoteException ; importera java.rmi.RMISecurityManager ; importera java.rmi.server.UnicastRemoteObject ; importera java.rmi.registry.* ; public class RmiServer utökar UnicastRemoteObject implementerar RmiServerIntf { public static final String MESSAGE = "Hej världen" ; public RmiServer () kastar RemoteException { } public String getMessage () { return MESSAGE ; } public static void main ( String args [] ) { System . ut . println ( "RMI-server startad" ); // Skapa och installera en säkerhetshanterare if ( System . getSecurityManager ( ) == null ) { System . setSecurityManager ( ny RMISecurityManager ()); System . ut . println ( "Säkerhetshanteraren installerad." ); } annat { System . ut . println ( "Säkerhetshanteraren finns redan." ); } försök med { //special exception-hanterare för att skapa register LocateRegistry . createRegistry ( 1099 ); System . ut . println ( "java RMI-registret skapat." ); } catch ( RemoteException e ) { //gör ingenting, fel betyder att registret redan finns System . ut . println ( "java RMI-registret finns redan." ); } försök { //Instantiate RmiServer RmiServer obj = ny RmiServer (); // Bind den här objektinstansen till namnet "RmiServer" Naming . rebind ( "//localhost/RmiServer" , obj ); System . ut . println ( "PeerServer bunden i registret" ); } catch ( Undantag e ) { System . fel . println ( "RMI-serverundantag:" + e ); e . printStackTrace (); } } }KlassRmiServerIntf − Den definierar gränssnittet som används av klienten och implementeras av servern.
importera java.rmi.Remote ; importera java.rmi.RemoteException ; public interface RmiServerIntf extends Remote { public String getMessage () throws RemoteException ; }Klassen RmiClientär en klient som använder en proxy för ett fjärrobjekt som finns på serversidan och anropar dess metoder för att hämta data. Om serverobjektet implementerar ett gränssnitt java.io.Serializableistället för java.rmi.Remote, kommer det att serialiseras och dess värde skickas till klienten. [1] .
importera java.rmi.Naming ; importera java.rmi.RemoteException ; importera java.rmi.RMISecurityManager ; public class RmiClient { // "obj" är referensen för fjärrobjektet RmiServerIntf obj = null ; public String getMessage () { try { obj = ( RmiServerIntf ) Namngivning . lookup ( "//localhost/RmiServer" ); returnera obj . getMessage (); } catch ( Undantag e ) { System . fel . println ( "RmiClient undantag: " + e ); e . printStackTrace (); tillbaka e . getMessage (); } } public static void main ( String args [] ) { // Skapa och installera en säkerhetshanterare if ( System . getSecurityManager () == null ) { System . setSecurityManager ( ny RMISecurityManager ()); } RmiClient cli = ny RmiClient (); System . ut . println ( cli.getMessage ( ) ); } }Innan du kör det här programmet måste du skapa en "Stub"-fil för det gränssnitt du använder. För att göra detta kan du använda RMI-kompilatorn - 'rmic'
Filen server.policykrävs för att ge servern rätt att ansluta TCP/IP till ett fjärrregister och en RMI-server.
bevilja { permission java . netto . SocketPermission "127.0.0.1:*" , "anslut, lös" ; tillstånd java . netto . SocketPermission "127.0.0.1:*" , "acceptera" ; };Server.policy-filen används med '-D'-argumentet i Java RTE :
java.exe -Djava.security.policy=server.policy RmiServerFilen client.policykrävs för att klienten ska kunna ansluta till RMI-servern över TCP/IP.
bevilja { permission java . netto . SocketPermission "127.0.0.1:*" , "anslut, lös" ; };Fil no.policy- rekommenderas för klient eller server vid anslutningsproblem.
bevilja { permission java . säkerhet . AllPermission ; };