1. Обзор
Когда двум JVM необходимо взаимодействовать, Java RMI — это один из вариантов, который нам нужен для этого. В этой статье мы запустим простой пример, демонстрирующий технологию Java RMI.
2. Создание сервера
Для создания RMI-сервера необходимо выполнить два шага:
- Создайте интерфейс, определяющий контракт клиент/сервер.
- Создайте реализацию этого интерфейса.
2.1. Определение контракта
Прежде всего, давайте создадим интерфейс для удаленного объекта. Этот интерфейс расширяет интерфейс маркера java.rmi.Remote .
Кроме того, каждый метод, объявленный в интерфейсе, выдает java.rmi.
Удаленное исключение
:
public interface MessengerService extends Remote {
String sendMessage(String clientMessage) throws RemoteException;
}
Однако обратите внимание, что RMI поддерживает полную спецификацию Java для сигнатур методов, если типы Java реализуют
java.io.Serializable
. ``
В следующих разделах мы увидим, как клиент и сервер будут использовать этот интерфейс.
Для сервера мы создадим реализацию, часто называемую Remote Object
.
Для клиента библиотека RMI динамически создаст реализацию, называемую Stub
.
2.2. Реализация
Кроме того, давайте реализуем удаленный интерфейс, снова называемый Remote Object
:
public class MessengerServiceImpl implements MessengerService {
@Override
public String sendMessage(String clientMessage) {
return "Client Message".equals(clientMessage) ? "Server Message" : null;
}
public String unexposedMethod() { /* code */ }
}
Обратите внимание, что мы исключили предложение throws
RemoteException
из определения метода.
Для нашего удаленного объекта было бы необычно генерировать RemoteException
, поскольку это исключение обычно зарезервировано для библиотеки RMI, чтобы вызвать ошибки связи с клиентом.
Преимущество его отсутствия также заключается в том, что наша реализация не зависит от RMI.
Также любые дополнительные методы, определенные в удаленном объекте, но не в интерфейсе, остаются невидимыми для клиента.
3. Регистрация службы
Как только мы создадим удаленную реализацию, нам нужно привязать удаленный объект к реестру RMI.
3.1. Создание заглушки
Во-первых, нам нужно создать заглушку нашего удаленного объекта:
MessengerService server = new MessengerServiceImpl();
MessengerService stub = (MessengerService) UnicastRemoteObject
.exportObject((MessengerService) server, 0);
Мы используем статический метод UnicastRemoteObject.exportObject
для создания нашей реализации-заглушки. Заглушка — это то, что делает волшебство связи с сервером по базовому протоколу RMI.
Первым аргументом exportObject
является объект удаленного сервера.
Второй аргумент — это порт, который exportObject
использует для экспорта удаленного объекта в реестр.
Нулевое значение указывает на то, что нам все равно, какой порт использует exportObject
, что является типичным и поэтому выбирается динамически.
К сожалению, метод exportObject()
без номера порта устарел.
3.2. Создание реестра
Мы можем создать реестр локально для нашего сервера или как отдельную автономную службу.
Для простоты мы создадим его локально для нашего сервера:
Registry registry = LocateRegistry.createRegistry(1099);
Это создает реестр, к которому заглушки могут быть привязаны серверами и обнаружены клиентами.
Кроме того, мы использовали метод createRegistry
, так как мы создаем реестр локально на сервере.
По умолчанию реестр RMI работает на порту 1099. Вместо этого в фабричном методе createRegistry
можно также указать другой порт .
Но в автономном случае мы бы вызвали getRegistry
, передав в качестве параметров имя хоста и номер порта.
3.3. Привязка заглушки
Следовательно, давайте привяжем нашу заглушку к реестру. Реестр RMI — это средство именования, такое как JNDI и т. д. Здесь мы можем следовать аналогичному шаблону, привязывая нашу заглушку к уникальному ключу:
registry.rebind("MessengerService", stub);
В результате удаленный объект теперь доступен любому клиенту, который может найти реестр.
4. Создание клиента
Наконец, давайте напишем клиент для вызова удаленных методов.
Для этого мы сначала найдем реестр RMI. Кроме того, мы будем искать заглушку удаленного объекта, используя ограниченный уникальный ключ.
И, наконец, мы вызовем метод sendMessage
:
Registry registry = LocateRegistry.getRegistry();
MessengerService server = (MessengerService) registry
.lookup("MessengerService");
String responseMessage = server.sendMessage("Client Message");
String expectedMessage = "Server Message";
assertEquals(expectedMessage, responseMessage);
Поскольку мы запускаем реестр RMI на локальном компьютере и используем порт по умолчанию 1099, мы не передаем никакие параметры в getRegistry
.
Действительно, если реестр находится на другом хосте или другом порту, мы можем указать эти параметры.
Как только мы найдем объект-заглушку с помощью реестра, мы можем вызывать методы на удаленном сервере.
5. Вывод
В этом руководстве мы получили краткое введение в Java RMI и то, как он может стать основой для клиент-серверных приложений. Следите за дополнительными сообщениями о некоторых уникальных функциях RMI!
Исходный код этого руководства можно найти на GitHub .