John Squirrels
Niveau
San Francisco

Java RMI

Udgivet i gruppen
Hej! I dag vil vi overveje et ret interessant emne: Java RMI. Dette står for Remote Method Invocation. Du kan bruge RMI til at tillade to programmer at kommunikere med hinanden, selvom de er på forskellige computere. Lyder det fedt? :) Og det er ikke så svært at gøre! I dagens lektion vil vi analysere elementerne i RMI-interaktionen og finde ud af, hvordan den konfigureres. Det første, vi har brug for, er en klient og en server. Vi behøver egentlig ikke dykke dybt ned i computerterminologi. Når det kommer til RMI, er der kun tale om to programmer. En af dem vil inkludere et objekt, og den anden vil kalde metoder på det objekt. Kalde metoder for et objekt, der findes i et andet program - nu er det noget, vi ikke har gjort endnu! Det er tid til at give det en chance! :) For at undgå at blive hængende, lad' s holde vores program simpelt. Generelt udfører en server nogle beregninger, som en klient anmoder om. Og sådan vil det være med os. Vores server vil være et simpelt regneprogram. Det vil kun have én metode:multiplicere() . Det vil gange to tal, der sendes til det af klientprogrammet, og derefter returnere resultatet. Først og fremmest har vi brug for en grænseflade:

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

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Hvorfor har vi brug for en grænseflade? Fordi RMI er afhængig af at oprette proxyer, som du har studeret i tidligere lektioner . Som du sikkert husker, arbejder vi med proxyer gennem grænseflader, ikke klasser. Der er 2 vigtige krav til vores grænseflade!
  1. Det skal udvide fjerngrænsefladen.
  2. Alle dens metoder skal kaste en RemoteException (IDE'en vil ikke gøre dette automatisk - du skal tilføje dette manuelt!).
Nu skal vi oprette en serverklasse, der implementerer vores Calculator- grænseflade. RMI i praksis - 2Også her er alt ganske enkelt:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

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

}
Der er ikke rigtig noget at kommentere her :) Nu skal vi skrive et serverprogram, der skal konfigurere og køre vores lommeregnerobjekt. Det vil se sådan ud:

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);

   }
}
Lad os finde ud af det :) I den første linje erklærer vi en eller anden strengvariabel:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
Denne streng er fjernobjektets unikke navn. Vores klientprogram bruger dette navn til at finde vores server: du vil se dette senere. Dernæst opretter vi vores lommeregnerobjekt:

final RemoteCalculationServer server = new RemoteCalculationServer();
Alt er klart her. Hvad der kommer næste er mere interessant:

final Registry registry = LocateRegistry.createRegistry(2732);
Dette registreringsobjekt er et register over fjernobjekter. Dette er objekter, som andre programmer kan få fjernadgang :) Vi sendte nummeret 2732 til LocateRegistry.createRegistry() metoden. Dette er portnummeret - et unikt nummer, som andre programmer vil bruge til at finde vores objektregister (igen, du vil se dette nedenfor). Går lige med... Lad os se, hvad der sker i næste linje:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
Vi skaber en stub i denne linje. En stub indkapsler hele fjernopkaldet. Du kan betragte dette som det vigtigste element i RMI. Hvad gør den?
  1. Den modtager alle oplysninger om et fjernopkald af en eller anden metode.
  2. Hvis metoden har parametre, vil stubben deserialisere dem. Vær opmærksom på dette punkt! Argumenterne, som du sender til de fjernkaldte metoder, skal kunne serialiseres (de vil trods alt blive transmitteret over netværket). Dette er ikke noget problem for os - vi sender bare numre. Men hvis du sender objekter, så glem ikke dette krav!
  3. Derefter kalder stubben den ønskede metode.
Vi videregiver vores lommeregnerserverobjekt til UnicastRemoteObject.exportObject() metoden. Sådan gør vi det muligt at fjernkalde dets metoder. Der er kun én ting tilbage at gøre:

registry.bind(UNIQUE_BINDING_NAME, stub);
Vi "registrerer" vores stub i fjernobjektregistret under det navn, vi fandt på i begyndelsen. Nu vil kunden kunne finde det! Måske har du bemærket, at vi satte programmets hovedtråd i dvale til sidst:

Thread.sleep(Integer.MAX_VALUE);
Vi skal bare have serveren til at køre i lang tid. I IDE'en vil vi samtidig starte to main()- metoder: For det første serverens main()-metode (i ServerMain- klassen , som vi allerede har skrevet), og for det andet klientens main()-metode (i ClientMain- klassen , som vi vil skrive nedenfor). Det er vigtigt, at serverprogrammet ikke afsluttes, mens vi starter klienten, så vi sætter den bare i dvale i lang tid. Under alle omstændigheder vil den blive ved med at køre :) Nu kan vi køre vores servers main() metode. Lad det køre og vent på, at klientprogrammet kalder en metode :) Lad os nu skrive klientprogrammet! Det vil sende tal til vores server til multiplikation.

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);
   }
}
Det ser simpelt ud. Men hvad sker der her? Først skal klienten kende det unikke navn på objektet, hvis metoder den vil kalde eksternt. Derfor oprettede vi i klientprogrammet den offentlige statiske endelige streng UNIQUE_BINDING_NAME = "server.calculator"; variabel. Dernæst får vi i main() -metoden adgang til registret over fjernobjekter. For at gøre dette skal vi kalde metoden LocateRegistry.getRegistry() og videregive portnummeret, der blev brugt til at oprette vores registreringsdatabasen i ServerMain-programmet (port 2732; dette nummer er kun et eksempel - du kan prøve at bruge et andet nummer):

final Registry registry = LocateRegistry.getRegistry(2732);
Nu mangler vi bare at få det ønskede objekt fra registreringsdatabasen! Det er nemt, fordi vi kender dets unikke navn!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Vær opmærksom på typestøbning. Vi caster det modtagne objekt til Calculator- grænsefladen, ikke til RemoteCalculationServer -klassen. Som vi sagde i begyndelsen af ​​lektionen, er RMI afhængig af en proxy, så fjernopkald er kun tilgængelige for metoderne til en grænseflade, ikke metoderne i en klasser. Til sidst kalder vi multiply() -metoden på vores objekt eksternt og sender resultatet til konsollen.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
ServerMain - klassens main()- metode har allerede kørt i lang tid. Nu er det tid til at køre main() metoden i klientprogrammet ( ClientMain )! Konsoludgang:

600
Det er det! Vores program (to programmer, faktisk!) gjorde hvad det skulle :) Hvis du har tid og lyst, kan du pifte det lidt op. Få for eksempel lommeregneren til at understøtte de fire almindelige aritmetiske operationer og videregive tal ikke som primitive typer, men som CalculationInstance(int x, int y) objekter. Vi ses i næste lektion! :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION