JavaRush /Blog Java /Random-PL /RMI: praktyka użytkowania

RMI: praktyka użytkowania

Opublikowano w grupie Random-PL
Cześć! Dzisiaj przyjrzymy się dość ciekawemu tematowi - RMI . Oznacza to zdalne wywołanie metody . RMI: praktyka użytkowania - 1Dzięki RMI możesz nauczyć dwa programy komunikować się ze sobą, nawet jeśli znajdują się na różnych komputerach. Brzmi nieźle? :) Ale to nie takie trudne! Na dzisiejszym wykładzie zrozumiemy z jakich części składa się interakcja RMI i jak ją skonfigurować. Pierwszą rzeczą, której potrzebujemy, jest klient i serwer . Nie musisz zagłębiać się w terminologię komputerową. W przypadku RMI są to po prostu dwa programy. Jedna z nich będzie zawierać jakiś obiekt, a druga będzie wywoływać metody tego obiektu. Wywoływanie metod obiektu w jednym programie, który znajduje się w innym programie - nigdy wcześniej tego nie robiliśmy! Czas spróbować! :) Żeby nie utonąć w dziczy niech nasz program będzie prosty. Ogólnie rzecz biorąc, serwery zwykle wykonują pewne obliczenia, o które prosi klient. U nas będzie tak samo. Jako serwer będziemy mieli prosty program kalkulatora. Będzie miała tylko jedną metodę - multiply(). Pomnoży dwie liczby wysłane do niego przez program kliencki i zwróci wynik. Przede wszystkim potrzebujemy interfejsu:
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Dlaczego potrzebujemy interfejsu? Faktem jest, że praca RMI opiera się na tworzeniu proxy, o czym uczyłeś się na jednym z poprzednich wykładów . A praca z proxy, jak zapewne pamiętasz, odbywa się właśnie na poziomie interfejsów, a nie klas. Istnieją 2 ważne wymagania dotyczące naszego interfejsu!
  1. Musi dziedziczyć interfejs tokena zdalnego.
  2. Wszystkie jego metody muszą zgłaszać wyjątek RemoteException (w IDE nie dzieje się to automatycznie, trzeba to napisać ręcznie!).
Teraz musimy stworzyć klasę serwera, która będzie implementować nasz interfejs Calculator. RMI: praktyka użytkowania - 2Wszystko tutaj jest również dość proste:
import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

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

}
Nie ma tu nawet za bardzo co komentować :) Teraz musimy napisać program serwerowy, który skonfiguruje i uruchomi naszą klasę kalkulatora serwerowego. Będzie to wyglądać tak:
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);

   }
}
Rozpracujmy to :) W pierwszej linii tworzymy coś w rodzaju zmiennej łańcuchowej:
public static final String UNIQUE_BINDING_NAME = "server.calculator";
Ten ciąg znaków jest unikalną nazwą zdalnego obiektu . Pod tą nazwą program kliencki będzie mógł znaleźć nasz serwer: zobaczysz to później. Następnie tworzymy obiekt naszego kalkulatora:
final RemoteCalculationServer server = new RemoteCalculationServer();
Tutaj wszystko jest jasne. Bardziej interesujące jest to:
final Registry registry = LocateRegistry.createRegistry(2732);
Ta rzecz zwana Rejestrem to rejestr usuniętych obiektów . „Usunięte” nie w tym sensie, że usunęliśmy je z komputera, ale w tym, że do obiektów z tego rejestru można uzyskać dostęp zdalny z innych programów :) LocateRegistry.createRegistry()Do metody przekazaliśmy numer 2732. Jest to numer portu. Jeśli nie wiesz, co to jest port, możesz przeczytać go tutaj , ale na razie musisz tylko pamiętać, że jest to unikalny numer, dzięki któremu inne programy mogą znaleźć nasz rejestr obiektów (zobaczysz to również poniżej). Przejdźmy dalej. Zobaczmy, co stanie się w następnym wierszu:
Remote stub = UnicastRemoteObject.exportObject(server, 0);
W tej linii tworzymy stub . Odcinek zawiera w sobie cały proces zdalnego połączenia. Można powiedzieć, że to najważniejszy element RMI. Co ona robi?
  1. Odbiera wszystkie informacje o zdalnym wywołaniu metody.
  2. Jeśli metoda ma parametry, kod pośredniczący je deserializuje. Zwróć uwagę na ten punkt! Parametry, które przekazujesz do metod wywołań zdalnych, muszą nadawać się do serializacji (w końcu będą przesyłane przez sieć). U nas nie ma takiego problemu – po prostu przekazujemy liczby. Ale jeśli przenosisz przedmioty, nie zapomnij o tym!
  3. Następnie wywołuje żądaną metodę.
UnicastRemoteObject.exportObject()Do metody przekazujemy obiekt naszego kalkulatora serwera. W ten sposób umożliwiamy zdalne wywoływanie jego metod. Pozostała nam tylko jedna rzecz do zrobienia:
registry.bind(UNIQUE_BINDING_NAME, stub);
„Rejestrujemy” nasz kod pośredniczący w zdalnym rejestrze obiektów pod nazwą, którą wymyśliliśmy na samym początku. Teraz klient może to znaleźć! Być może zauważyłeś, że na koniec uśpiliśmy główny wątek programu:
Thread.sleep(Integer.MAX_VALUE);
Musimy po prostu utrzymać serwer działający przez długi czas. W IDEa uruchomimy jednocześnie dwie metody main(): najpierw serwerową (w klasie, którą ServerMainjuż napisaliśmy), a następnie kliencką (w klasie, którą ClientMainnapiszemy poniżej). Ważne jest, aby program serwera nie zawiesił się podczas uruchamiania klienta, dlatego po prostu uśpiliśmy go na dłuższy czas. To nadal będzie działać :) Teraz możemy uruchomić main()naszą metodę serwerową. Pozwól mu działać i poczekaj, aż program kliencki wywoła jakąś metodę :) Teraz napiszmy program kliencki! Wyśle liczby na nasz serwer w celu pomnożenia.
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);
   }
}
Wygląda na nieskomplikowaną. Co tu się dzieje? Po pierwsze, klient musi znać unikalną nazwę obiektu, którego metody będzie wywoływał zdalnie. Dlatego też w programie klienckim utworzyliśmy również zmienną public static final String UNIQUE_BINDING_NAME = "server.calculator"; , następnie w metodzie main()uzyskujemy dostęp do rejestru obiektów zdalnych. W tym celu musimy wywołać metodę LocateRegistry.getRegistry()i przekazać tam numer portu, na którym został utworzony nasz rejestr w programie ServerMain - port 2732 (ten numer został wybrany jako przykład, możesz spróbować użyć innego):
final Registry registry = LocateRegistry.getRegistry(2732);
Teraz pozostaje nam już tylko pobrać z rejestru pożądany przedmiot! To proste, bo znamy jego unikalne imię!
Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Zwróć uwagę na rzutowanie typu. Wynikowy obiekt rzutujemy na interfejs, Calculatora nie na konkretną klasę RemoteCalculationServer . Jak powiedzieliśmy na początku wykładu, RMI opiera się na wykorzystaniu proxy, dlatego zdalne wywołanie jest dostępne tylko dla metod interfejsów, a nie klas. Na koniec zdalnie wywołujemy metodę multiply()na naszym obiekcie i wypisujemy wynik na konsolę.
int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
Już dawno uruchomiliśmy metodę main()w klasie , czas uruchomić metodę w programie klienta ! Wydajność konsoli: 600 To wszystko! Nasz program (nawet dwa!) z powodzeniem spełnił swoją funkcję :) Jeśli masz czas i chęć, możesz go trochę urozmaicić. Na przykład upewnij się, że kalkulator obsługuje wszystkie cztery standardowe operacje, a nie liczby, ale obiekt jest przekazywany jako parametry . Jako materiał dodatkowy możesz zapoznać się z artykułami i przykładami - tutaj: ServerMainmain()ClientMainCalculationInstance(int x, int y) Do zobaczenia na kolejnych zajęciach! :)
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION