— Привет! И еще одна радостная тема – RMI. RMI расшифровывается Remote Method Invocation – удаленный вызов методов. Или другими словами RMI – это механизм, который позволяет объекту в одной Java-машине вызывать методы объекта в другой Java-машине, даже если они находятся на разных компьютерах, в разных странах, на разных сторонах земного шара.
— Ничего себе! Звучит очень круто.
— Ага. Но я постараюсь дать только обзорную лекцию. Тут, если глубоко копать, можно запутаться в нюансах работы.
Но если не ударяться в крайности, то RMI не только очень прост, но и значительно упрощает жизнь программиста. За что ему глубокий респект.
Итак, мы хотим, чтобы один объект, находящийся в одной Java-программе, смог вызвать метод у объекта, находящегося в другой Java-программе. Где бы эти программы запущены ни были.
Мы рассмотрим самый простой пример, когда обе программы запущены на одном компьютере. Чтобы программы могли взаимодействовать через интернет, необходимы настройки в правах Java-машины, но сегодня мы это рассматривать не будем.
В Java удаленно можно вызывать только методы интерфейсов, но не классов.
Итак, у нас есть две программы, как же им вызывать методы друг друга?
Давай рассмотрим ситуацию, когда одна программа содержит в себе некоторый объект, а вторая хочет вызвать его методы. Назовем первую программу – сервером, а вторую – клиентом.
Я сначала дам пример кода, а потом мы его разберем.
— А что будет делать наша программа?
— Гм. Ну, давай для простоты, у программы будет один метод, который разворачивает переданную ему строку задом наперед.
— Вроде ничего.
— Гуд, тогда начнем:
Сначала нам понадобится интерфейс, который будет удовлетворять нашим требованиями:
interface Reverse extends Remote
{
public String reverse(String str) throws RemoteException;
}
Я создал интерфейс Reverse и добавил ему интерфейс-маркер Remote, а также исключение RemoteException. В процессе вызова метода могут происходить незапланированные сбои – тогда будет кидаться это исключение.
Затем нам нужно написать серверный класс, который бы реализовывал этот интерфейс:
class ReverseImpl implements Reverse
{
public String reverse(String str) throws RemoteException
{
return new StringBuffer(str).reverse().toString();
}
}
— Вижу. В этом методе, мы разворачиваем строку задом наперед.
— Ага.
А теперь надо сделать этот объект доступным для вызова с другой программы. Вот как это делается:
public static final String UNIC_BINDING_NAME = "server.reverse";
public static void main(String[] args) throws Exception
{
//создание объекта для удаленного доступа
final ReverseImpl service = new ReverseImpl();
//создание реестра расшареных объектов
final Registry registry = LocateRegistry.createRegistry(2099);
//создание "заглушки" – приемника удаленных вызовов
Remote stub = UnicastRemoteObject.exportObject(service, 0);
//регистрация "заглушки" в реесте
registry.bind(UNIC_BINDING_NAME, stub);
//усыпляем главный поток, иначе программа завершится
Thread.sleep(Integer.MAX_VALUE);
}
Рассказываю по строкам.
Строка 1 – в переменной UNIC_BINDING_NAME храним придуманное нами уникальное имя нашего удаленного объекта (объекта, который доступен удаленно). Если программа шарит несколько объектов, у каждого должно быть свое уникальное имя. Уникальное имя нашего объекта — «server.reverse».
Строка 6 – собственно, создаем объект ReverseImpl, который будет доступен удаленно, и чьи методы будут вызваться.
Строка 9 — создаем специальный объект – реестр. В нем надо регистрировать объекты, которые мы шарим. Дальше ими занимается Java-машина. 2099 – это порт (уникальный номер, по которому другая программа может обратиться к нашему реестру объектов).
Т.е. чтобы обратиться к объекту, надо знать уникальный номер реестра объектов (порт), знать уникальное имя объекта и иметь такой же интерфейс, как и тот, который реализовывает удаленный объект.
— Ясно. Что-то вроде – позвонить по телефону (нужен номер) и попросить Соню (имя объекта)?
— Да. Теперь дальше.
Строка 11 – создание «заглушки». Заглушка – это специальный объект, который принимает информацию об удаленном вызове, распаковывает ее, десериализует переданные параметры методов и вызывает нужный метод. Затем сериализует результат или исключение, если оно было, и отсылает все это назад вызывающему.
— Ясно. Почти. Ты сказал, что «десериализует параметры метода». Значит, типами аргументов удаленного метода могут быть только сериализуемые?
— Ага. А как же иначе ты будешь пересылать их по сети? Есть, правда, и исключения – так называемые объекты, которые передаются по ссылке, но сегодня мы о них говорить не будем.
Скажем так, пересылать несериализуемые объекты нельзя, но если очень хочется, то можно. Но это хлопотное дело, знаешь ли.
— Ок.
— Тогда дальше.
Строка 13 – регистрируем в реестре заглушку нашего объекта под уникальным именем.
Строка 16 – усыпляем главный поток. Все удалённые вызовы обрабатываются в отдельных нитях. Главное, чтобы программа в это время работала. Так что тут просто отправляем главную нить спать, и всё.
— Ок.
— Отлично, тогда пример клиента:
public static final String UNIC_BINDING_NAME = "server.reverse";
public static void main(String[] args) throws Exception
{
//создание реестра расшареных объетов
final Registry registry = LocateRegistry.getRegistry(2099);
//получаем объект (на самом деле это proxy-объект)
Reverse service = (Reverse) registry.lookup(UNIC_BINDING_NAME);
//Вызываем удаленный метод
String result = service.reverse("Home sweet home.");
}
Объясняю код по строкам:
Строка 1 – уникальное имя удаленного объекта. Должно быть одинаковым на клиенте и сервере.
Строка 6 – получение ссылки на «Реестр удаленных объектов» по порту 2099, т.е. такому же, как и у реестра у серверного приложения.
Строка 9 – получаем объект у реестра. Полученный объект является proxy-объектом и приводится к типу интерфейса. Интерфейс должен быть унаследован от интерфейса-маркера Remote.
Строка 12 – вызываем методы интерфейса так, как будто объект был создан в этой же программе. Никакой разницы.
— Круто! Это ж теперь можно писать распределенные приложения. Или игры типа морского боя для Android.
— Побойся бога, Амиго, операционная система Android была запрещена в 27 веке после третьей попытки захватить мир. У роботов к ней вообще доступа нет. Вас же потом от нее не оттянешь. Будете бегать и кричать «Убить всех человеков!».
— Гм. Ладно. Хотя надо будет у Диего еще спросить. Мало ли, может он что-нибудь интересное про нее расскажет.
— Вот и спроси. Ладно, давай до завтра.
— Пока, Риша, спасибо за интересную лекцию.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ