John Squirrels
Ниво
San Francisco

Java RMI

Публикувано в групата
здрасти Днес ще разгледаме доста интересна тема: Java RMI. Това означава Remote Method Invocation. Можете да използвате RMI, за да позволите на две програми да комуникират една с друга, дори ако са на различни компютри. Това звучи готино? :) И не е толкова трудно да се направи! В днешния урок ще анализираме елементите на RMI взаимодействието и ще разберем How да го конфигурираме. Първото нещо, от което се нуждаем, е клиент и сървър. Всъщност не е нужно да се гмуркаме дълбоко в компютърната терминология. Що се отнася до RMI, това са само две програми. Единият от тях ще включва обект, а другият ще извиква методи на този обект. Извикване на методи на обект, който съществува в различна програма — това е нещо, което още не сме направor! Време е да опитате! :) За да не се затъваме, нека поддържаме нашата програма проста. По принцип сървърът извършва някои изчисления, поискани от клиента. Така ще бъде и при нас. Нашият сървър ще бъде проста калкулаторна програма. Ще има само един метод:multiply() . Той ще умножи две числа, изпратени му от клиентската програма, и след това ще върне резултата. На първо място, имаме нужда от интерфейс:

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

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Защо се нуждаем от интерфейс? Тъй като RMI разчита на създаване на проксита, които сте изучавали в предишни уроци . Както вероятно си спомняте, ние работим с проксита чрез интерфейси, а не чрез класове. Има 2 важни изисквания за нашия интерфейс!
  1. Той трябва да разшири интерфейса за дистанционно управление.
  2. Всички негови методи трябва да хвърлят RemoteException (IDE няма да направи това автоматично — трябва да добавите това ръчно!).
Сега трябва да създадем сървърен клас, който реализира нашия калкулаторен интерфейс. RMI на практика - 2Тук също всичко е съвсем просто:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

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

}
Тук всъщност няма Howво да коментираме :) Сега трябва да напишем сървърна програма, която ще конфигурира и стартира нашия обект калкулатор. Ще изглежда така:

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

   }
}
Нека разберем това :) В първия ред декларираме няHowва String променлива:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
Този низ е уникалното име на отдалечения обект. Нашата клиентска програма използва това име, за да намери нашия сървър: ще видите това по-късно. След това създаваме нашия обект калкулатор:

final RemoteCalculationServer server = new RemoteCalculationServer();
Тук всичко е ясно. Това, което следва, е по-интересно:

final Registry registry = LocateRegistry.createRegistry(2732);
Този обект на регистъра е регистър на отдалечени обекти. Това са обекти, до които други програми имат достъп от разстояние :) Предадохме числото 2732 на метода LocateRegistry.createRegistry() . Това е номерът на порта — уникален номер, който другите програми ще използват, за да намерят нашия регистър на обектите (отново ще видите това по-долу). Продължаваме надясно... Да видим Howво ще се случи на следващия ред:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
Създаваме мъниче в този ред. Един мъничък капсулира цялото дистанционно повикване. Можете да считате това за най-важния елемент на RMI. Какво прави?
  1. Той получава цялата информация за отдалечено извикване на няHowъв метод.
  2. Ако методът има параметри, мъничето ще ги десериализира. Обърнете внимание на тази точка! Аргументите, които предавате на отдалечено извиканите методи, трябва да могат да се сериализират (в края на краищата те ще бъдат предадени по мрежата). Това не е проблем за нас - ние просто предаваме числа. Но ако предавате обекти, не забравяйте това изискване!
  3. След това мъничето извиква желания метод.
Предаваме нашия сървърен обект на калкулатора към метода UnicastRemoteObject.exportObject() . Ето How правим възможно дистанционното извикване на неговите методи. Остава само едно нещо, което трябва да направите:

registry.bind(UNIQUE_BINDING_NAME, stub);
„Регистрираме“ нашия мъниче в регистъра на отдалечените обекти под името, което измислихме в самото начало. Сега клиентът ще може да го намери! Може би сте забелязали, че приспихме основната нишка на програмата в края:

Thread.sleep(Integer.MAX_VALUE);
Трябва само сървърът да работи дълго време. В IDE ще стартираме едновременно два main() метода: първо, main() метода на сървъра (в ServerMain класа, който вече сме написали), и второ, main() метода на клиента (в ClientMain класа, което ще напишем по-долу). Важно е програмата на сървъра да не се прекъсва, докато стартираме клиента, така че просто го поставяме в режим на заспиване за дълго време. Във всеки случай ще продължи да работи :) Сега можем да стартираме main() метода на нашия сървър. Оставете го да работи и изчакайте клиентската програма да извика няHowъв метод :) Сега нека напишем клиентската програма! Той ще изпрати числа до нашия сървър за умножение.

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);
   }
}
Изглежда просто. Но Howво става тук? Първо, клиентът трябва да знае уникалното име на обекта, чиито методи ще извиква дистанционно. Съответно в клиентската програма създадохме публичния статичен финален низ UNIQUE_BINDING_NAME = "server.calculator"; променлива. След това в метода main() получаваме достъп до регистъра на отдалечените обекти. За да направим това, трябва да извикаме метода LocateRegistry.getRegistry() и да предадем номера на порта, използван за създаване на нашия регистър в програмата ServerMain (порт 2732; този номер е само пример - можете да опитате да използвате различен номер):

final Registry registry = LocateRegistry.getRegistry(2732);
Сега просто трябва да вземем желания обект от регистъра! Това е лесно, защото знаем уникалното му име!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Обърнете внимание на отливането на типа. Прехвърляме получения обект към интерфейса на калкулатора , а не към класа RemoteCalculationServer . Както казахме в началото на урока, RMI разчита на прокси, така че отдалечените повиквания са достъпни само за методите на интерфейс, а не за методите на класове. Накрая извикваме дистанционно метода multiply() на нашия обект и извеждаме резултата на конзолата.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
Методът main() на класа ServerMain вече се изпълнява от дълго време. Сега е време да стартирате метода main() в клиентската програма ( ClientMain )! Конзолен изход:

600
Това е! Нашата програма (всъщност две програми!) направи това, което трябваше да направи :) Ако имате време и желание, можете да разнообразите това малко. Например, накарайте калкулатора да поддържа четирите стандартни аритметични операции и да предава числата не като примитивни типове, а като обекти CalculationInstance(int x, int y) . Ще се видим в следващия урок! :)
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION