John Squirrels
Nivel
San Francisco

Java RMI

Publicat în grup
Bună! Astăzi vom lua în considerare un subiect destul de interesant: Java RMI. Aceasta înseamnă Remote Method Invocation. Puteți utiliza RMI pentru a permite două programe să comunice între ele, chiar dacă sunt pe computere diferite. Sună mișto? :) Și nu este atât de greu de făcut! În lecția de astăzi, vom analiza elementele interacțiunii RMI și vom descoperi cum să o configuram. Primul lucru de care avem nevoie este un client și un server. Nu trebuie să ne aprofundăm în terminologia computerizată. Când vine vorba de RMI, acestea sunt doar două programe. Unul dintre ele va include un obiect, iar celălalt va apela metode pe acel obiect. Apelarea metodelor unui obiect care există într-un alt program - acum este ceva ce nu am făcut încă! Este timpul să încerci! :) Pentru a evita să te blochezi, haideți menținem programul nostru simplu. În general, un server efectuează unele calcule pe care le solicită un client. Și așa va fi și cu noi. Serverul nostru va fi un simplu program de calculator. Va avea o singură metodă:înmulțire() . Acesta va înmulți două numere trimise de programul client și apoi va returna rezultatul. În primul rând, avem nevoie de o interfață:

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

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
De ce avem nevoie de o interfață? Pentru că RMI se bazează pe crearea de proxy, pe care le-ați studiat în lecțiile anterioare . După cum probabil vă amintiți, lucrăm cu proxy prin interfețe, nu prin clase. Există 2 cerințe importante pentru interfața noastră!
  1. Trebuie să extindă interfața de la distanță.
  2. Toate metodele sale trebuie să arunce o excepție RemoteException (IDE-ul nu va face acest lucru automat - trebuie să adăugați acest lucru manual!).
Acum trebuie să creăm o clasă de server care implementează interfața Calculator . RMI în practică - 2Și aici totul este destul de simplu:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

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

}
Nu este nimic de comentat aici :) Acum trebuie să scriem un program server care va configura și rula obiectul calculatorului. Va arata asa:

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

   }
}
Să ne dăm seama :) În prima linie, declarăm o variabilă String:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
Acest șir este numele unic al obiectului la distanță. Programul nostru client folosește acest nume pentru a găsi serverul nostru: veți vedea asta mai târziu. În continuare, creăm obiectul nostru calculator:

final RemoteCalculationServer server = new RemoteCalculationServer();
Totul este clar aici. Ce urmează este mai interesant:

final Registry registry = LocateRegistry.createRegistry(2732);
Acest obiect Registry este un registru al obiectelor de la distanță. Acestea sunt obiecte pe care alte programe le pot accesa de la distanță :) Am trecut numărul 2732 la metoda LocateRegistry.createRegistry() . Acesta este numărul portului — un număr unic pe care alte programe îl vor folosi pentru a găsi registrul nostru de obiecte (din nou, veți vedea asta mai jos). Deplasându-ne chiar de-a lungul... Să vedem ce se întâmplă în rândul următor:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
Creăm un stub în această linie. Un stub încapsulează întregul apel de la distanță. Puteți considera că acesta este cel mai important element al RMI. Ce face?
  1. Primește toate informațiile despre un apel de la distanță al unei anumite metode.
  2. Dacă metoda are parametri, stub-ul îi va deserializa. Fii atent la acest punct! Argumentele pe care le transmiteți metodelor apelate de la distanță trebuie să fie serializabile (la urma urmei, vor fi transmise prin rețea). Aceasta nu este o problemă pentru noi - doar transmitem numere. Dar dacă transmiteți obiecte, nu uitați de această cerință!
  3. După aceea, stub-ul apelează metoda dorită.
Trecem obiectul server al calculatorului la metoda UnicastRemoteObject.exportObject() . Acesta este modul în care facem posibilă apelarea de la distanță a metodelor sale. Mai rămâne un singur lucru de făcut:

registry.bind(UNIQUE_BINDING_NAME, stub);
Ne „înregistrăm” stub-ul în registrul de obiecte la distanță sub numele pe care l-am creat la început. Acum clientul o va putea găsi! Poate ați observat că am pus firul principal al programului în somn la sfârșit:

Thread.sleep(Integer.MAX_VALUE);
Avem nevoie doar ca serverul să ruleze mult timp. În IDE, vom lansa simultan două metode main() : în primul rând, metoda main() a serverului (în clasa ServerMain , pe care am scris-o deja), și în al doilea rând, metoda main() a clientului (în clasa ClientMain , pe care o vom scrie mai jos). Este important ca programul server să nu fie terminat în timp ce pornim clientul, așa că îl punem în stare de repaus pentru o lungă perioadă de timp. În orice caz, va continua să ruleze :) Acum putem rula metoda main() a serverului nostru. Lăsați-l să ruleze și așteptați ca programul client să apeleze o metodă :) Acum să scriem programul client! Va trimite numere la serverul nostru pentru multiplicare.

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);
   }
}
Pare simplu. Dar ce se întâmplă aici? În primul rând, clientul trebuie să cunoască numele unic al obiectului ale cărui metode le va apela de la distanță. În consecință, în programul client, am creat șirul final static public UNIQUE_BINDING_NAME = "server.calculator"; variabil. Apoi, în metoda main() , obținem acces la registrul de obiecte la distanță. Pentru a face acest lucru, trebuie să apelăm metoda LocateRegistry.getRegistry() și să transmitem numărul portului folosit pentru a crea registrul nostru în programul ServerMain (portul 2732; acest număr este doar un exemplu - puteți încerca să utilizați un alt număr):

final Registry registry = LocateRegistry.getRegistry(2732);
Acum trebuie doar să obținem obiectul dorit din registry! Acest lucru este ușor, pentru că îi știm numele unic!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Acordați atenție turnării tipului. Am aruncat obiectul primit în interfața Calculator , nu în clasa RemoteCalculationServer . După cum am spus la începutul lecției, RMI se bazează pe un proxy, așa că apelurile la distanță sunt disponibile numai pentru metodele unei interfețe, nu pentru metodele unei clase. În cele din urmă, apelăm de la distanță metoda multiplicly() pe obiectul nostru și trimitem rezultatul în consolă.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
Metoda main() a clasei ServerMain rulează deja de mult timp. Acum este timpul să rulați metoda main() în programul client ( ClientMain )! Ieșire din consolă:

600
Asta este! Programul nostru (două programe, de fapt!) a făcut ceea ce trebuia să facă :) Dacă aveți timp și dorință, puteți condimenta puțin acest lucru. De exemplu, faceți ca calculatorul să accepte cele patru operații aritmetice standard și să treceți numerele nu ca tipuri primitive, ci ca obiecte CalculationInstance(int x, int y) . Ne vedem la următoarea lecție! :)
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION