Было бы проще, если бы все компоненты выполнялись в одном и том же куче одной виртуальной машины Java на одном компьютере, но на практике мы часто сталкиваемся с не такой единственной ситуацией. Если клиент — это просто устройство, которое может выполнять Java, что делать. делать? Что, если по соображениям безопасности доступ к базе данных смогут получить только программы на сервере?
Мы знаем, что в большинстве случаев вызовы методов происходят между двумя объектами в одной куче. Что, если вы хотите вызвать методы для объектов на разных машинах?
Обычно мы получаем информацию с одного компьютера на другой через поток ввода/вывода сокета, открываем соединение сокета другого компьютера, а затем получаем выходной поток для записи данных. Но если мы хотим вызвать другой компьютер на ваш. компьютер, каковы методы объектов на другой виртуальной машине Java? Конечно, мы можем сами определить и спроектировать протокол связи для вызова, а затем передать результаты выполнения обратно через Socket, а также это может быть похоже на вызов методов на локальной машине, то есть, если мы хотим вызывать удаленные объекты (например, как и другие кучи) ), но должно быть как обычный звонок.
Вот что нам приносит RMI.
Проектирование удаленных вызовов процедур
Нужно создать 4 вещи: сервер, клиент, вспомогательные средства сервера и вспомогательные средства клиента.
1. Создайте клиентское и серверное приложения. Серверное приложение — это удаленный сервис, объект с методами, которые будет вызывать клиент.
2. Создайте помощники на стороне клиента и сервера. Они будут обрабатывать все основные детали сетевого ввода/вывода клиента и сервера, создавая впечатление, что клиент и программа обрабатывают локальные вызовы.
Задачи вспомогательных средств Вспомогательные средства — это объекты, которые фактически осуществляют связь. Они создают у клиента ощущение, будто он вызывает локальный объект. Клиентский объект выглядит так, как будто он вызывает удаленный метод, но на самом деле он просто вызывает метод A. прокси-сервер, который локально обрабатывает информацию о сокетах и потоковой передаче. На стороне сервера вспомогательные средства сервера будут подключаться через сокет. Запрос от клиентского средства анализирует упакованную информацию, а затем вызывает реальную службу, поэтому вызов является локальным для объекта службы. После того как вспомогательное средство службы получает возвращаемое значение, оно упаковывает его и отправляет обратно (через поток вывода сокета). ) помощнику клиента Помощник клиента распакует информацию и передаст ее объекту клиента.
Процесс вызова метода
1. Клиентский объект вызывает doBigThing() для объекта вспомогательного объекта.
2. Вспомогательные средства клиента упаковывают информацию о вызове и отправляют ее по сети на вспомогательные средства сервера.
3. Вспомогательное средство на стороне сервера декодирует информацию от вспомогательного средства на стороне клиента и использует ее для вызова реальной службы.
Схема, описывающая этот процесс, выглядит следующим образом:
JavaRMI предоставляет вспомогательные объекты на стороне клиента и на стороне сервера.
В Java RMI помог нам создать вспомогательные средства на стороне клиента и на стороне сервера. Он также знает, как сделать вспомогательные средства на стороне клиента похожими на настоящие сервисы. Другими словами, RMI знает, как предоставлять одинаковые методы для клиентских вызовов. .
Кроме того, RMI предоставляет всю инфраструктуру, необходимую для выполнения, включая запросы к службам и вспомогательные средства, которые позволяют клиентам находить и получать клиентов (реальных агентов обслуживания).
При использовании RMI нет необходимости писать какие-либо сетевые программы или программы ввода-вывода. Вызов клиента удаленного метода аналогичен вызову метода на той же виртуальной машине Java.
Общие вызовы немного отличаются от вызовов RMI. Хотя для клиента этот вызов метода выглядит локальным, но вспомогательное средство клиента будет выполнять вызов через сеть. Этот вызов в конечном итоге задействует сокеты и потоки. Он начинается как локальный вызов. и агент преобразует его в удаленный. Способ отправки промежуточной информации с виртуальной машины Java на виртуальную машину Java зависит от протокола, используемого объектом вспомогательного объекта.
При использовании RMI вы должны выбрать протокол: JRMP или JRMP — это собственный протокол RMI. Он предназначен для удаленных вызовов между Java. С другой стороны, IIOP создан для CORBA, что позволяет нам вызывать Java. Для объектов или других типов удаленных методов CORBA обычно более проблематичен, чем RMI, потому что, если оба конца не являются Java, произойдет множество ужасных операций перевода и диалога.
Нас интересуют только операции Java-Java, поэтому мы будем использовать довольно простой RMI.
В RMI вспомогательные средства на стороне клиента называются заглушками, а вспомогательные средства на стороне сервера — скелетами.
Как создать удаленный сервис
1.Создать удаленный интерфейс
Удаленный интерфейс определяет методы, которые клиент может вызывать удаленно. Это полиморфный класс как служба. И заглушка, и служба будут реализовывать этот интерфейс.
2. Реализовать удаленный интерфейс
Это фактически исполняемый класс. Он реализует методы, определенные в интерфейсе. Это объект, который будет вызывать клиент.
3. Используйте rmic для создания заглушки и скелета.
И у клиента, и у сервера есть помощники. Нам не нужно создавать эти классы или генерировать исходный код этих классов. Это будет автоматически обработано при выполнении инструмента rmic, прикрепленного к JDK.
4. Запускаем RMIregistry (рмирегистри).
rmiregistry похож на телефонную книгу, отсюда пользователь получит прокси (заглушку/вспомогательный объект клиента).
5. Запустите удаленный сервис.
Объект службы должен начать выполнение. Класс, реализующий службу, запустит экземпляр службы и зарегистрирует его в RMIRegistry. Только после регистрации он сможет обслуживать пользователя.
Код сервера
Определить интерфейс
/**
*
*MyRemote.java
*
* Функция: TODO
* Имя класса: MyRemote.java.
*
* Обновлен держатель персонажа и новый контент.
*â€────────────────────────────────────────────
* V1.00 19 марта 2013 г. Первая версия модуля Su Ruo
*
* Copyright (c) Dennisit Corporation, 2013. Все права защищены.
*
* Электронная почта: <a href="mailto:[email protected]">Отправить письмо</a>
*
*
* Remote — это отмеченный интерфейс, что означает отсутствие методов. Однако для RMI он имеет особое значение, поэтому необходимо соблюдать это правило.
* Обратите внимание, что здесь используются расширения, а интерфейсы могут наследовать другие интерфейсы.
*
*/
общедоступный интерфейс MyRemote расширяет Remote{
/**
* Удаленный интерфейс определяет методы, которые клиент может вызывать удаленно. Это полиморфный класс как служба.
* Мобилизуйте заглушку, реализующую этот интерфейс, и поскольку эта заглушка будет выполнять работу сети и ввода-вывода, могут произойти разные вещи.
* Проблема: клиент обрабатывает или объявляет исключения для распознавания этого типа риска. Если метод объявляет исключение в интерфейсе, вызовите этот метод.
* Все процедуры должны обрабатывать или повторно объявлять это исключение.
*
* Параметры и возвращаемые значения удаленных методов должны быть примитивными или сериализуемыми. Любые параметры удаленных методов будут.
* Пакет передается по сети, и когда он завершается сериализацией, возвращаемое значение остается тем же. Поэтому, если используется пользовательский тип.
*, он должен быть сериализован
* @возвращаться
* @throws RemoteException
* Все методы интерфейса должны объявлять RemoteException.
*/
public StringsayHello() выдает RemoteException;
}
/**
*
*MyRemoteImpl.java
*
* Функция: TODO
* Имя класса: MyRemoteImpl.java.
*
* Обновлен держатель персонажа и новый контент.
*â€────────────────────────────────────────────
* V1.00 19 марта 2013 г. Первая версия модуля Su Ruo
*
* Copyright (c) Dennisit Corporation, 2013. Все права защищены.
*
* Электронная почта: <a href="mailto:[email protected]">Отправить письмо</a>
*
* Чтобы стать объектом удаленной службы, объект должен иметь функции, связанные с удаленным доступом. Самый простой способ — наследовать UnicastRemoteObject.
* (из java.rmi.server), чтобы позволить этому родительскому классу выполнять всю работу
*
*/
публичный класс MyRemoteImpl расширяет UnicastRemoteObject и реализует MyRemote{
/**
* Конструктор родительского класса объявляет исключение, поэтому вы должны написать конструктор, поскольку это означает, что ваш конструктор будет вызывать рискованный программный код.
*
* У UnicastRemoteObject есть небольшая проблема: его конструктор выдает RemoteException. Единственный способ справиться с ней.
* Объявите конструктор для своей собственной реализации, чтобы было место для объявления RemoteException. Когда класс инициализируется, родительский класс.
* Конструктор обязательно будет вызван. Если конструктор родительского класса выдает исключение, то пользовательский конструктор, который мы также должны объявить, выдаст исключение.
* @throws RemoteException
*/
protected MyRemoteImpl() выдает RemoteException {
}
/**
* Реализовать все методы исходящего интерфейса, но не нужно объявлять RemoteException
*/
@Override
публичная строкаsayHello(){
return "сервер говорит: rmi, привет, мир!";
}
public static void main(String[] args) {
пытаться {
/**
* У нас уже есть удаленная служба, и мы должны разрешить удаленным пользователям доступ к ней. Это можно сделать, инициализировав ее и добавив в реестр RMI.
* (Она должна быть запущена, иначе эта программа выйдет из строя). При регистрации объекта система RMI добавит заглушку в реестр,
* Потому что это то, что нужно клиенту. Используйте rebind() java.rmi.Naming для регистрации службы.
*/
Сервис MyRemote = новый MyRemoteImpl();
/**
* Создайте удаленный объект, а затем используйте static Naming.rebind() для создания ассоциации. Зарегистрированное имя будет предоставлено для запроса клиента.
*/
Naming.rebind("Удаленный Hello World", сервис);
} catch (Исключение е) {
е.printStackTrace();
}
}
}
общественный недействительный exec () {
пытаться {
/**
* Клиент должен получить объект-заглушку, поскольку клиент должен вызвать его метод. Это зависит от реестра RMI. Клиент будет запрашивать телефон следующим образом.
* Выполните поиск в том же каталоге, чтобы найти службы с совпадающими именами.
* Клиент запрашивает RMIRegistry и возвращает объект-заглушку.
* Naming.lookup("rmi://127.0.0.1/Remote Hello World");
* Описание параметра
* rmi://127.0.0.1/Remote Привет, мир
* 127.0.0.1 представляет имя хоста или IP-адрес хоста.
* Удаленное имя Hello World должно совпадать с зарегистрированным именем.
*
*/
Служба MyRemote = (MyRemote)Naming.lookup("rmi://127.0.0.1/Remote Hello World");
Строка tmp = service.sayHello();
System.out.println(tmp);
} catch (Исключение е) {
е.printStackTrace();
}
}
public static void main(String[] args) {
новый MyRemoteClient().exec();
}
}
Инструмент rmic, входящий в состав JDK, сгенерирует два класса: заглушку и скелет, в зависимости от реализации службы. Он добавит _Stub или _Skeleton после имени удаленной реализации в соответствии с правилами именования. У rmic есть несколько вариантов, включая отказ от создания скелетов, просмотр исходного кода сгенерированных классов или использование IIOP в качестве протокола связи. Сгенерированные классы будут помещены в текущий каталог. Помните, что rmic должен иметь возможность находить реализованные классы. Поэтому вам может потребоваться выполнить rmic из каталога, где находится реализация (на практике вам может потребоваться учитывать структуру каталогов и полное имя пакета, для простоты пакет здесь не используется)
Вызовите командную строку, чтобы запустить rmiregistry. Убедитесь, что вы запустили его из каталога, к которому есть доступ. Самый простой способ — запустить его из каталога класса.
Рабочий скриншот выглядит следующим образом
Уведомление:
Клиент использует интерфейс для вызова метода на заглушке. Виртуальная машина Java клиента должна иметь класс-заглушку, но клиент не будет ссылаться на класс-заглушку в программном коде. Клиент всегда управляет реальным удаленным объектом через интерфейс.
Сервер должен иметь заглушки и скелеты, а также сервисные и удаленные интерфейсы. Для этого требуется класс заглушки, поскольку заглушка будет заменена реальной службой, подключенной к RMIRegistry.
Распространенные ошибки при использовании RMI:
1. Забыл запустить rmiregistry перед запуском удаленной службы (rmiregistry необходимо запустить перед использованием Naming.rebind() для регистрации службы)
2. Забыли сделать сериализуемыми параметры и типы возвращаемых значений (это не будет обнаружено во время компиляции и будет обнаружено только во время выполнения)
3. Забудьте передать класс-заглушку клиенту
RMI очень подходит для написания и запуска удаленных сервисов, но мы не будем использовать только RMI для выполнения сервисов веб-сайтов. Для крупномасштабных приложений уровня предприятия нам нужны больше и лучшие функции, такие как управление транзакциями, крупномасштабная одновременная обработка и т. д. и безопасность. И управление базами данных и т. д. Для этого требуется использование EnterpriseApplicationServer.
Сервер JavaEE включает в себя веб-сервер и сервер Enterprise JavaBeans (EJB). Сервер EJB действует между вызовами RMI и уровнем обслуживания.
Применение RMI в JINI
Jini также использует RMI (хотя можно использовать и другие протоколы), но у него есть еще несколько ключевых функций.
1. Адаптивное открытие
2. Самовосстанавливающиеся сети
Клиент RMI должен сначала получить адрес и имя удаленной службы. Программный код запроса клиента должен содержать IP-адрес или имя хоста удаленной службы (поскольку на нем находится RMIRegistry) и имя, зарегистрированное службой.
Но при использовании JINI пользователям нужно знать только одно — интерфейс, реализованный сервисом. Вот и все!
Jini использует службу поиска, которая более мощна и более адаптируема, чем RMIRegistry. Поскольку Jini автоматически размещает рекламу в сети, когда служба запросов подключается к сети, она будет использовать технологию многоадресной рассылки IP для отправки информации по всей сети. подключается к сети после трансляции службы запросов, и клиент также может отправлять сообщения по всей сети для запроса.
Когда служба подключается к сети, она динамически исследует службу запросов JINI в сети и подает заявку на регистрацию. При регистрации служба отправит сериализованный объект в службу запросов. Этот объект может быть заглушкой удаленной службы RMI. драйвер сетевого устройства или даже сам сервис, который может выполняться на клиенте. И прописан реализованный интерфейс.
Как работает адаптивное исследование
1. Служба запросов Jini запускается в сети и использует технологию многоадресной IP-адресации для продвижения себя.
2. Другая запущенная служба Jini попытается зарегистрироваться во вновь запущенной службе запросов. Она регистрирует функцию, а не имя, то есть реализованный интерфейс, а затем отправляет сериализованный объект в службу запросов.
3. Интернет-клиенты хотят получить что-то для реализации ScientificCalculator, но не знают, где это найти, поэтому обращаются в службу запросов.
4. Служба запросов отвечает на результаты запроса.
Работа самовосстанавливающейся сети
1. Определенная служба Jini требует регистрации, и служба запросов предоставляет аренду. Вновь зарегистрированные службы должны регулярно продлевать аренду. В противном случае служба запросов будет предполагать, что служба запросов будет стремиться предоставить точную и достоверную информацию. полный доступный статус сервисной сети.
2. Служба отключена из-за завершения работы, поэтому аренда не обновляется, и служба запросов запускается.