Академический Документы
Профессиональный Документы
Культура Документы
By jGuru
Об этом кратком курсе
Февраль 2000г.
Java Developer ConnectionSM (JDC) представляет «Краткий курс», который знакомит вас с Remote Method
Invocation API, написанным jGuru (прежнее название - MageLang Institute), являющимся обладателем
лицензии Java™ Software. Jguru – ведущий поставщик обучающих курсов по технологии Java™ и
регулярный спонсор JDC с 1996 года.
jGuru является преданным участником в деле расширения сообщества Java™ посредством пропаганды,
обучения и программного обеспечения с 1995 года. Вы можете найти дополнительную информацию об их
деятельности, включая поддерживаемые сообществом FAQ (часто задаваемые вопросы) и интерактивное
обучение, на www.jGuru.com.
Цели
После завершения курса вы поймете:
Предварительные условия
Общее знакомство с концепциями объектно-ориентированного программирования и с языком
программирования Java. Если вы не знакомы с этими понятиями, смотрите «Учебник по Java». Упражнения
требуют умения модифицировать и создавать программы Java.
Об авторе
Если у вас есть другие комментарии или идеи для будущих статей, пожалуйста, напишите
нам.
Краткий курс
В этом курсе рассмотрены основы технологии Remote Method Invocation (RMI), относящейся к платформе
Java 2™.
Содержание курса
• Введение в распределенные вычисления с использованием RMI
o Цели
o Сравнение распределенных и нераспределенных Java-программ
• Использование RMI
o Интерфейсы
o Реализация
o Заглушки и скелеты
o Хост-сервер
o Клиент
o Запуск системы RMI
• Параметры в RMI
• Альтернативные реализации
• Дополнительные ресурсы
o Книги и статьи
Этот курс представляет собой углубленное введение в эту универсальную технологию. RMI получила
значительное развитие в JDK 1.1 и во многом была улучшена в Java 2 SDK. При необходимости, различия
между этими двумя версиями будут отмечены.
Цели
В данном разделе рассматривается архитектура RMI с точки зрения распределенных или удаленных
объектов Java, а также их отличие от локальных объектов Java. Архитектура RMI определяет поведение
объектов, время и способы возникновения исключительных ситуаций, способы управления памятью и
способы передачи параметров и их возврата из удаленных методов.
Разработчики RMI стремились сделать использование распределенных Java-объектов таким же, как и
использование локальных объектов. В следующей таблице перечислены некоторые важные отличия.
Не беспокойтесь о том, что не все отличия вам понятны. Все прояснится после рассмотрения архитектуры
RMI. Вы можете использовать эту таблицу в качестве ссылки во время изучения RMI.
Архитектура RMI основана на одном важном принципе: определение поведения и реализация этого
поведения считаются разными понятиями. RMI дает возможность разделить и выполнить на разных JVM
код, определяющий поведение, и код, реализующий поведение.
Конкретно в RMI определение удаленной службы кодируется при помощи интерфейса Java. Реализация
удаленной службы кодируется в классе. Таким образом, ключ к пониманию RMI – помнить, что
интерфейсы определяют поведение, а классы определяют реализацию.
Помните, что интерфейсы Java не содержат исполняемого кода. RMI поддерживает два класса,
реализующих один и тот же интерфейс. Первый класс является реализацией поведения и исполняется на
сервере. Второй класс работает как промежуточный интерфейс для удаленной службы и исполняется на
клиентской машине. Это показано на следующей диаграмме.
Клиентская программа вызывает методы прокси-объекта, RMI передает запрос на удаленную JVM и
направляет его в реализацию объекта. Любые возвращаемые из реализации значения передаются назад в
прокси-объект и затем в клиентскую программу.
Следующий уровень – уровень удаленной ссылки. Этот уровень понимает, как интерпретировать и
управлять ссылками на удаленные объекты служб. В JDK 1.1 этот уровень соединяет клиентов с
удаленными объектами служб, которые исполняются на сервере. Это соединение является связью типа один
к одному (однонаправленное соединение). В Java 2 SDK этот уровень был расширен поддержкой активации
пассивных удаленных объектов при помощи технологии Remote Object Activation.
При использовании уровневой архитектуры каждый из уровней может быть изменен или заменен без
воздействия на остальную систему. Например, транспортный уровень может быть заменен протоколом
UDP/IP без изменения остальных уровней.
Уровень заглушки и скелета RMI расположен непосредственно перед разработчиком Java. На этом уровне
RMI использует прокси-модель проектирования, которая описана в книге Gamma, Helm, Johnson и Vlissides
«Design Patterns». В прокси-модели объект одного контекста представляется другим (прокси-объектом) в
отдельном контексте. Прокси-объект знает, как направлять вызовы методов между этими объектами. На
следующей диаграмме классов показана прокси-модель.
В прокси-модели, используемой в RMI, роль прокси выполняет класс заглушки, а роль RealSubject
выполняет класс, реализующий удаленную службу.
Скелет является вспомогательным классом, который создается для использования RMI. Скелет понимает,
как взаимодействовать с заглушкой при RMI-соединении. Скелет поддерживает общение с заглушкой; он
читает параметры для вызова метода из соединения, производит вызов объекта, реализующего удаленную
службу, принимает возвращаемое значение и записывает его обратно в заглушку.
В реализации RMI Java 2 SDK новый протокол связи сделал классы скелетов не нужными. RMI использует
отражение для установления соединения с объектом удаленной службы. Вы должны использовать классы и
объекты скелетов только в JDK 1.1 и совместимых с ним реализациях систем.
Уровни удаленных ссылок определяют и поддерживают семантику вызовов соединения RMI. Этот уровень
предоставляет объект RemoteRef, который обеспечивает соединение с объектами, реализующими
удаленные службы.
Объекты заглушки используют метод invoke() в объекте RemoteRef для направления вызова метода.
Объект RemoteRef понимает семантику вызова удаленных служб.
Реализация RMI в JDK 1.1 обеспечивает только один способ соединения клиентов с реализациями
удаленных служб: однонаправленное соединение типа точка-точка. Перед тем, как клиент сможет
использовать удаленную службу, экземпляр объекта, реализующего ее, должен быть создан на сервере и
экспортирован в систему RMI. (Если это основная служба, она также должна быть поименована и
зарегистрирована в реестре RMI).
Реализация RMI в Java 2 SDK добавляет новую семантику для соединения клиент-сервер. В этой версии
RMI поддерживает способные к активизации удаленные объекты. Когда производится вызов метода прокси
для такого объекта, RMI определяет, находится ли объект, реализующий удаленную службу, в пассивном
состоянии. Если да, то RMI создаст экземпляр объекта и восстановит его состояние из дискового файла. Как
только объект активизируется в памяти, он начинает вести себя так же, как и объект, реализующий
удаленную службу JDK 1.1.
Доступны и другие типы семантики соединений. Например, в случае широковещательного соединения, один
прокси-объект может передать запрос метода нескольким реализациям одновременно и принять первый
ответ (это уменьшает время отклика и, возможно, повышает доступность объекта). В будущем Sun
возможно добавит дополнительные типы семантики в RMI.
Транспортный уровень
Транспортный уровень осуществляет соединение между различными JVM. Все соединения представляют
собой основанные на потоках сетевые соединения, использующие TCP/IP.
Даже если две JVM работают на одном и том же физическом компьютере, они соединяются через стек
сетевых протоколов TCP/IP. (Вот почему вы должны иметь действующую конфигурацию TCP/IP на вашем
компьютере для выполнения упражнений этого курса). На следующей диаграмме показаны TCP/IP
соединения между разными JVM.
Как вы знаете, протокол TCP/IP обеспечивает постоянное, основанное на потоках, соединение между двумя
машинами. Этот соединение основано на адресе IP и номере порта. Обычно вместо IP-адреса используется
имя DNS; это означает, что можно говорить, например, о соединении между
flicka.magelang.com:3452 и rosa.jguru.com:4432. В текущей реализации RMI соединения
TCP/IP используются как основа для всех межмашинных соединений.
На вершине TCP/IP RMI использует протокол уровня соединения, называемый Java Remote Method Protocol
(JRMP). JRMP является частным, основанным на потоках, протоколом, который только частично
специфицирован в настоящее время в двух версиях. Первая версия была выпущена в реализации RMI в JDK
1.1 и требовала использования классов скелетов на сервере. Вторая версия была выпущена с Java 2 SDK.
Она была оптимизирована по производительности и не требовала использования скелетных классов.
(Обратите внимание, что некоторые альтернативные реализации, такие как BEA Weblogic и NinjaRMI, не
используют RMI, а используют вместо него свои собственные протоколы уровня соединения. Voyager от
ObjectSpace распознает JRMP и будет взаимодействовать с RMI на уровне соединения.)
Sun и IBM совместно разработали следующую версию RMI, называемую RMI-IIOP, которая будет доступна
в версии 1.3 Java 2 SDK. Интересным моментом в RMI-IIOP является то, что она будет использовать
протокол Object Management Group (OMG) Internet Inter-ORB Protocol, IIOP для взаимодействия между
клиентами и серверами.
OMG представляет собой группу из более чем 800 членов, которая определяет независимую от
производителей, распределенную объектную архитектуру, называемую Common Object Request Broker
Architecture (CORBA). Клиенты и серверы CORBA Object Request Broker (ORB) взаимодействуют между
собой, используя IIOP. С принятием в CORBA расширения Objects-by-Value и предложений Java Language to
IDL Mapping работа была направлена на интеграцию RMI и CORBA. Эта новая реализация RMI-IIOP
поддерживает большинство возможностей RMI, за исключением:
• java.rmi.server.RMISocketFactory
• UnicastRemoteObject
• Unreferenced
• Интерфейсов DGC
Транспортный уровень RMI был разработан для осуществления соединения между клиентами и сервером
даже с учетом сетевых помех.
Хотя транспортный уровень предпочитает использовать несколько TCP/IP соединений, некоторые сетевые
конфигурации разрешают только одно TCP/IP-соединение между клиентом и сервером (некоторые броузеры
ограничивают апплеты одним сетевым соединением с их сервером).
В этом случае, транспортный уровень распределяет несколько виртуальных соединений внутри одного
TCP/IP-соединения.
RMI может использовать много различных служб каталогов, включая Java Naming and Directory Interface
(JNDI). RMI и сама включает в себя простую службу, называемую реестром RMI, rmiregistry. Реестр
RMI работает на каждой машине, содержащей объекты удаленных служб и принимающей запросы на
обслуживание, по умолчанию используя порт 1099.
На хосте программа сервера создает удаленную службу, предварительно создавая локальный объект,
реализующий эту службу. Затем она экспортирует этот объект в RMI. Как только объект экспортирован,
RMI создает службу прослушивания, ожидающую соединения с клиентом и запроса службы. После
экспорта, сервер регистрирует объект в реестре RMI, используя общедоступное имя.
На стороне клиента к реестру RMI доступ обеспечивается через статический класс Naming. Он
предоставляет метод lookup(), который клиент использует для запросов к реестру. Метод lookup() принимает
URL, указывающий на имя хоста и имя требуемой службы. Метод возвращает удаленную ссылку на
обслуживающий объект. URL принимает следующий вид:
rmi://<host_name>
[:<name_service_port>]
/<service_name>
где host_name - это имя, распознаваемое в локальной сети (LAN), или DNS-имя в сети Internet.
Необходимо только указать name_service_port, если служба имен исполняется на порте, отличном от
принимаемого по умолчанию 1099.
Использование RMI
Сейчас наступило время создать рабочую RMI-систему и получить практический опыт. В данном разделе,
вы создадите простую удаленную службу, реализующую калькулятор, и попробуете использовать ее из
клиентской программы.
В следующих разделах вы создадите простую RMI-систему пошаговым способом. Советуем создать новый
подкаталог на вашем компьютере и создавать файлы по мере чтения текста.
Для упрощения задачи вы будете использовать один и тот же каталог для кода как клиента, так и сервера.
При запуске клиента и сервера из одного и того же каталога вам не придется настраивать HTTP или FTP
серверы для доступа к файлам классов. (Использование серверов HTTP и FTP в качестве поставщиков
файлов классов детально рассматривается в разделе «Распространение и установка программного
обеспечения RMI»)
Если предположить, что RMI-система уже спроектирована, для ее создания необходимо выполнить
следующие шаги:
Первым шагом является написание и компилирование Java-кода для интерфейсов служб. Интерфейс
Calculator определяет все удаленные возможности, предлагаемые службой:
Обратите внимание, что этот интерфейс расширяет интерфейс Remote, и в сигнатуре каждого
метода определяется, что он может генерировать объект RemoteException.
Скопируйте этот файл в ваш каталог и откомпилируйте его при помощи компилятора Java:
>javac Calculator.java
2. Реализация
3. Заглушки и скелеты
Дальше вы используете компилятор RMI, rmic, для генерации файлов заглушки и скелета.
Компилятор запускается с указанием файла класса, реализующего удаленную службу.
>rmic CalculatorImpl
Попробуйте выполнить это в вашем каталоге. После запуска rmic вы должны найти файл
Calculator_Stub.class и, если вы используете Java 2 SDK, Calculator_Skel.class.
Удаленные службы RMI должны быть помещены в процесс сервера. Класс CalculatorServer
является очень простым сервером, предоставляющим простые элементы для размещения.
import java.rmi.Naming;
public CalculatorServer() {
try {
Calculator c = new CalculatorImpl();
Naming.rebind("
rmi://localhost:1099/
CalculatorService", c);
} catch (Exception e) {
System.out.println("Trouble: " + e);
}
}
5. Клиент
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
6. Запуск RMI-системы
Теперь вы готовы к запуску системы! Вы должны запустить три консоли, одну для сервера, одну
для клиента и одну для реестра RMI.
rmiregistry
Если все пройдет хорошо, реестр начнет работать, и вы можете перейти к следующей консоли.
>java CalculatorServer
>java CalculatorClient
1
9
18
3
Вот и все: вы создали работающую систему RMI. Даже если вы запустили три консоли на одном и том же
компьютере, RMI использует стек протоколов TCP/IP вашей сети для взаимодействия между тремя
отдельными JVM. Это вполне законченная RMI-система.
Упражнения
Параметры в RMI
RMI поддерживает вызовы методов удаленных объектов. Если эти вызовы содержат параметры или
принимают возвращаемое значение, как RMI передает их между JVM? Какая используется семантика?
Поддерживает ли RMI передачу по значению или передачу по ссылке? Ответ зависит от того, являются ли
параметры переменными простого типа, объектами или удаленными объектами.
Когда в метод передаются данные простого типа (boolean, byte, short, int, long, char, float,
или double), используется передача по значению. Механизм передачи в качестве параметров объектов
является более сложным. Вспомните, что объекты расположены в памяти, и к ним можно получить доступ
при помощи одной или нескольких переменных-ссылок. И хотя в следующем фрагменте программы
кажется, что в метод println()передается объект
String s = "Test";
System.out.println(s);
Теперь давайте посмотрим, как RMI передает параметры и возвращаемые значения между удаленными
JVM.
Простые параметры
Когда в качестве параметра в удаленный метод передается простой тип данных, RMI-система передает их по
значению. RMI делает копию простого типа данных и передает ее в удаленный метод. Если метод
возвращает простой тип данных, также используется передача по значению.
Значения передаются между JVM в стандартном, машинно-независимом формате. Это позволяет JVM,
работающим на разных платформах, надежно взаимодействовать друг с другом.
Объектные параметры
Когда в удаленный метод передается объект, семантика отличается от семантики, используемой в случае с
одной JVM. RMI передает между JVM сам объект, а не ссылку на него. Т.е., объект передается по значению.
Подобным же образом, когда удаленный метод возвращает объект, в вызывающую программу передается
полная копия объекта.
В отличие от простых типов данных, передача объекта в удаленную JVM – не простая задача. Объект Java
может быть простым и самодостаточным, но может содержать сложную, похожую на граф, структуру
ссылок на другие объекты Java. Поскольку различные JVM не разделяют динамическую память, RMI
должен послать указанный объект и все объекты, на которые он ссылается. (Передача большой структуры
объектов может потребовать много времени процессора и пропускной способности сети.)
RMI использует технологию, называемую сериализацией объектов, для преобразования объекта в линейный
формат, который затем может быть передан по сети. Сериализация объекта, по существу, выравнивает
объект и все объекты, на которые он ссылается. Сериализованные объекты могут быть десериализованы в
памяти удаленной JVM и подготовлены к использованию программой Java.
RMI представляет третий тип параметров: удаленные объекты. Как вы уже видели, удаленная программа
может получить ссылку на удаленный объект через реестр RMI. Существует другой способ передачи
клиенту ссылки на удаленный интерфейс – она может быть возвращена клиенту из вызова метода. В
следующем коде для получения ссылки на удаленную службу Account используется метод
getAccount()службы BankManager.
BankManager bm;
Account a;
try {
bm = (BankManager) Naming.lookup(
"rmi://BankServer
/BankManagerService"
);
a = bm.getAccount( "jGuru" );
// Код, использующий счет
}
catch (RemoteException re) {
}
public Account
getAccount(String accountName) {
// Код для поиска соответствующего счета
AccountImpl ai =
// возврат найденной ссылки
return AccountImpl;
}
Когда метод возвращает локальную ссылку на экспортированный удаленный объект, RMI не возвращает
этот объект. Вместо него он подставляет другой объект (удаленный прокси-объект для данной службы) в
поток возвращаемых данных.
Обратите внимание, что когда клиенту А возвращается объект AccountImpl, прокси-объект Account
замещается. Последовательные вызовы метода продолжают передавать ссылку сначала клиенту В, а затем
назад серверу. На протяжении этого процесса ссылки продолжают обращаться к одному экземпляру
удаленной службы.
Что особенно интересно отметить, когда ссылка возвращается назад на сервер, она не преобразовывается в
локальную ссылку на реализованный объект. Это дает увеличение скорости, а поддержка такой косвенной
передачи дает гарантию того, что семантика использования удаленной ссылки не нарушается.
Упражнение
3. Параметры RMI
Для достижения этого клиент тоже должен работать как сервер RMI. Здесь нет ничего особенного,
поскольку RMI работает одинаково хорошо между всеми компьютерами. Однако, расширение клиентом
java.rmi.server.UnicastRemoteObject может быть не практичным. В этих случаях удаленный
объект может подготовить себя для удаленного использования, вызвав статический метод
UnicastRemoteObject.exportObject (<remote_object>).
Упражнение
4. Обратные вызовы RMI-клиента
Для целей этого раздела предполагается, что общий процесс разработки DC-системы привел вас к тому
моменту, когда вы должны подумать о размещении обработки на узлах сети, и определить, как установить
систему на каждом сетевом узле.
Для запуска RMI-приложения файлы поддерживающих классов должны быть расположены в таких местах,
где бы они могли быть найдены сервером и клиентами.
Если вы знаете, какие файлы должны быть размещены на различных узлах сети, то сделать их доступными
для каждого загрузчика классов JVM не составит труда.
Разработчики RMI расширили концепцию загрузки классов, включив загрузку классов из серверов HTTP и
FTP. Это является мощным расширением, поскольку означает, что классы могут быть размещены в одном
или в небольшом количестве мест, но в то же время все узлы в RMI-системе смогут получить нужный для
функционирования класс.
RMI поддерживает удаленную загрузку классов при помощи RMIClassLoader. Если на клиенте или
сервере выполняется RMI-система и для дальнейшей работы необходимо загрузить класс из удаленного
места, вызывается метод RMIClassLoader.
Способ загрузки классов управляется множеством свойств. Эти свойства могут быть установлены при
запуске JVM:
Если удаленная JVM нуждается в файле классов для объекта, она ищет встроенный URL и связывается с
сервером по этому URL для загрузки файла.
Используя различные комбинации доступных системных свойств, может быть создано большое количество
различных системных конфигураций RMI.
Closed. Все классы, используемые клиентами и сервером, должны быть расположены в JVM и ссылка на
это место должна быть указана в переменной окружения CLASSPATH. Динамическая загрузка классов не
поддерживается.
Client Dynamic. Основные классы загружаются из места, которое указано в переменной окружения
CLASSPATH JVM клиента. Классы поддержки загружаются при помощи
java.rmi.server.RMIClassLoader из HTTP или FTP-сервера по сети из места, указанного сервером.
Server Dynamic. Основные классы загружаются из места, которое указано в переменной окружения
CLASSPATH JVM клиента. Классы поддержки загружаются при помощи
java.rmi.server.RMIClassLoader из HTTP или FTP-сервера по сети из места, указанного клиентом.
Bootstrap client. В этой конфигурации весь код клиента загружается из HTTP или FTP-сервера по
сети. Единственный код, расположенный на клиентской машине, - это небольшой начальный загрузчик.
Bootstrap server. В этой конфигурации весь код сервера загружается из HTTP или FTP-сервера по
сети. Единственный код, расположенный на серверной машине, - это небольшой начальный загрузчик.
Упражнение этого раздела включает создание конфигурации bootstrap client. Внимательно следуйте
указаниям, так как необходимо разместить и откомпилировать разные файлы в разных каталогах.
Упражнение
5. Пример начальной загрузки
Брандмауэр
Любое сетевое корпоративное приложение, которое должно работать вне границ интранет, неизбежно
столкнется с брандмауэрами. В общем случае, брандмауэры блокируют весь сетевой трафик, за
исключением трафика, проходящего через определенные «хорошо известные» порты.
Поскольку транспортный уровень RMI открывает динамические соединения сокетов между клиентом и
сервером, трафик JRMP обычно блокируется большинством брандмауэров. К счастью, разработчики RMI
предвидели эту проблему. Ее решение обеспечивается самим транспортным уровнем RMI. Для прохождения
через брандмауэры RMI использует HTTP-туннелирование, помещая вызовы RMI в запрос HTTP POST.
Теперь исследуем, как работает HTTP-туннелирование трафика RMI, более детально рассмотрев возможные
сценарии: RMI-клиент, сервер или оба вместе могут исполняться за брандмауэром. На следующей
диаграмме показан сценарий, когда RMI-клиент, расположенный за брандмауэром, взаимодействует с
внешним сервером.
В этом сценарии транспортный уровень при попытке установить соединение с сервером блокируется
брандмауэром. Если это происходит, транспортный уровень RMI автоматически повторяет попытку,
помещая данные вызова JRMP в запрос HTTP POST. Заголовок HTTP POST для вызова выглядит так:
http://hostname:port
Если клиент находится за брандмауэром, важно также установить в соответствующее значение системное
свойство http.proxyHost. Поскольку большинство брандмауэров распознают HTTP-протокол,
указанный прокси-сервер должен быть способен направлять запрос прямо в порт, который прослушивает
удаленный сервер. Как только заключенные в HTTP данные JRMP принимаются сервером, они
автоматически декодируются и отправляются по назначению транспортным уровнем RMI. Ответ также
передается клиенту в виде заключенных в HTTP данных.
На следующей диаграмме показан сценарий, когда и клиент и сервер находятся за брандмауэром, или когда
прокси-сервер клиента может направлять данные только в HTTP-порт, имеющий номер 80.
В этом случае транспортный уровень RMI использует еще один дополнительный обходной уровень.
Причиной этого является то, что клиент не может больше передавать заключенные в HTTP JRMP-вызовы в
произвольные порты, поскольку сервер находится за брандмауэром. Вместо этого, транспортный уровень
RMI размещает JRMP-вызов внутри HTTP-пакетов и передает эти пакеты в порт 80 сервера. Заголовок
HTTP POST имеет теперь следующую форму:
http://hostname:80/cgi-bin/java-rmi?forward=<port>
Это вызывает выполнение сценария CGI, java-rmi.cgi, который в свою очередь вызывает локальную
JVM, распаковывает HTTP-пакет и направляет вызов серверному процессу в назначенный порт. RMI JRMP-
ответы от сервера передаются назад как пакеты HTTP REPLY в нужный порт клиента, где RMI опять
распаковывает информацию и передает ее в соответствующую заглушку RMI.
Естественно, для того, чтобы все это работало, сценарий java-rmi.cgi, который включен в стандартный
JDK 1.1 или в платформу Java 2, должен: быть предварительно сконфигурирован, указывать путь к
интерпретатору Java и располагаться в каталоге веб-сервера cgi-bin. Также очень важно при запуске RMI-
сервера указывать полное доменное имя хоста в системном свойстве для устранения любых проблем
разрешения DNS-имен, например:
java.rmi.server.hostname=host.domain.com
Примечание: Вместо использования CGI-сценария для направления вызова более эффективной является
реализация той же задачи с использованием сервлета. Вы можете получить исходный код такого сервлета из
RMI FAQ от Sun (http://java.sun.com/products/jdk/1.2/docs/guide/rmi/faq.html).
Необходимо отметить, что, несмотря на встроенный механизм прохождения через брандмауэр, RMI
испытывает значительное снижение производительности из-за HTTP-туннелирования. Существуют также и
другие трудности при использовании HTTP-туннелирования. Например, ваше RMI-приложение не сможет
больше мультиплексировать JRMP-вызовы в одном соединении, поскольку в этом случае применяется
дискретный протокол типа запрос-ответ. Кроме того, использование сценария java-rmi.cgi открывает
довольно большую дыру в безопасности вашего сервера, так как теперь сценарий может перенаправить
любой входящий запрос на любой порт, полностью обходя механизм защиты брандмауэра. Разработчики
должны также отметить, что использование HTTP-туннелирования запрещает RMI-приложениям
использовать обратные вызовы, что может быть основным ограничением при разработке. Поэтому, если
клиент обнаружит брандмауэр, он всегда может запретить имеющуюся по умолчанию возможность HTTP-
туннелирования, установив свойство:
java.rmi.server.disableHttp=true
Одним из требований к разработке RMI была ее бесшовная интеграция в язык программирования Java,
включая и сборку мусора. Разработка эффективного сборщика мусора для одной машины является тяжелой
задачей; разработка распределенного сборщика мусора является очень тяжелой задачей.
Интерфейс к DGC (распределенный сборщик мусора) скрыт на уровне заглушек и скелетов. Однако
удаленный объект может реализовать интерфейс java.rmi.server.Unreferenced и получить
уведомление через метод unreferenced, когда нет больше ни одного клиента, содержащего живую
ссылку.
В дополнение к механизму подсчета ссылок живая ссылка в клиенте имеет срок аренды с указанным
временем. Если клиент не обновляет соединение к удаленному объекту до истечения срока аренды, ссылка
считается мертвой и удаленный объект может быть утилизирован сборщиком мусора. Время аренды
управляется системным свойством java.rmi.dgc.leaseValue. Его значение указывается в
миллисекундах и по умолчанию равно 10 минутам.
Из-за такой семантики сборки мусора, клиент должен быть подготовлен для работы с объектами, которые
могут «исчезать».
Упражнение
6. Распределенная сборка мусора
Та же самая причина, по которой RMI делает легкой разработку какого-либо распределенного приложения,
может сделать трудным перемещение объектов между JVM. Если вы объявляете, что объект реализует
интерфейс java.rmi.Remote, RMI будет защищать его от сериализации и передачи между JVM в
качестве параметра. Вместо передачи класса реализации для интерфейса java.rmi.Remote RMI
замещает класс заглушки. Так как это замещение происходит во внутреннем коде RMI, никто не может
перехватить эту операцию.
Существуют два различных пути для решения этой проблемы. Первый заключается в ручной сериализации
удаленного объекта и передачи его в другую JVM. Для этого есть две стратегии. Первая стратегия – создать
ObjectInputStream и ObjectOutputStream соединения между двумя JVM. При этом вы можете
явно поместить удаленный объект в поток. Второй путь – сериализовать объект в массив byte и передать
массив byte как возвращаемое значение в вызове RMI-метода. Оба этих способа требуют кодирования на
уровне ниже RMI, и это может привести к дополнительному кодированию и сложностям в эксплуатации.
Во второй стратегии вы можете использовать модель делегирования. Согласно этой модели вы размещаете
основную функциональность в классе, который:
- Не реализует java.rmi.Remote
- Реализует java.io.Serializable
Теперь рассмотрим основные блоки этой модели. Обратите внимание, что это очень простой пример.
Реальный пример будет иметь значительное количество локальных полей и методов.
interface RemoteModelRef
extends java.rmi.Remote
{
String getVersionNumber()
throws java.rmi.RemoteException;
}
Реализация удаленной службы принимает ссылку на LocalModel и делегирует реальную работу этому
объекту:
//Делегируйте в реализацию
//локальной модели
public String getVersionNumber()
throws java.rmi.RemoteException
{
return lm.getVersionNumber();
}
}
И, наконец, вы определяете удаленную службу, обеспечивающую доступ к клиентам. Это делается при
помощи интерфейса java.rmi.Remote и его реализации:
LocalModel getLocalModel()
throws java.rmi.RemoteException;
}
public class RemoteModelMgrImpl
extends
java.rmi.server.UnicastRemoteObject
implements RemoteModelMgr
{
LocalModel lm;
RemoteModelImpl rmImpl;
public RemoteModelMgrImpl()
throws java.rmi.RemoteException
{
super();
}
//Создание экземпляра
//Remote Interface Wrapper
if (null == rmImpl)
{
rmImpl = new RemoteModelImpl (lm);
}
//Инсталляция delgatee
if (null == lm)
{
lm = new LocalModel();
}
return lm;
}
}
Упражнения
7. Сериализация удаленных объектов: Сервер
8. Сериализация удаленных объектов: Клиент
Альтернативные реализации
Этот курс рассматривает реализацию архитектуры RMI от Sun. Существуют и другие реализации,
например:
• NinjaRMI
Свободно распространяемая реализация, созданная в University of California, Berkeley. Ninja
подерживает JDK 1.1 версию RMI с расширениями.
• BEA Weblogic Server
BEA Weblogic Server является высокопроизводительным, безопасным сервером приложений,
поддерживающим RNI, Microsoft COM, CORBA, EJB (Enterprise JavaBeans) и другие службы.
• Voyager
Voyager от ObjectSpace поддерживает RMI вместе с собственной службой DOM, CORBA, EJB,
Microsoft DCOM и службы транзакций.
Дополнительные ресурсы
Книги и статьи
• Design Patterns, by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides (The Gang of Four)
• Sun's RMI FAQ
• RMI over IIOP
• RMI-USERS Mailing List Archive
• Implementing Callbacks with Java RMI, by Govind Seshadri, Dr. Dobb's Journal, March 1998
Упражнения
Добро пожаловать в раздел «Упражнения jGuru» курса «Основы RMI».
Эти упражнения иллюстрируют использование библиотеки Remote Method Invocation (RMI) для реализации
распределенных объектов.
Содержание упражнений
• Об упражнениях
o Анатомия упражнения
o Цели разработки упражнений
Об упражнениях
Упражнение jGuru является гибким упражнением, обеспечивающим различные уровни помощи,
соответствующие требованиям студентов. Некоторые студенты могут выполнить упражнение, используя
только информацию и список задач в теле упражнения; некоторые захотят просмотреть несколько советов
(Помощь); в то время как остальные захотят использовать пошаговое руководство для успешного
выполнения упражнения (Решение). Но так как в дополнение к помощи предоставляется полное решение,
они смогут выполнить другие упражнения, зависящие от пропущенных.
Анатомия упражнения
Каждое упражнение включает список требуемых упражнений, скелетный код для начала, ссылки на
необходимые страницы API и текстовое описание образовательной цели упражнения. В дополнение, кнопки
отсылают вас к следующей информации:
• Помощь: Помощь или советы по текущему упражнению и аннотированное решение. Для простоты
использования информация о задаче на странице помощи дублирует фактическую информацию,
вставленную ниже ее.
• Решение: Тэг <applet> и исходный код Java приводят к ожидаемому поведению.
• Документация по API: Прямая ссылка на любую необходимую документацию по API.
«Чистый экран»
Расширение
Восстановление
Для того чтобы облегчить обучение, упражнения, там где возможно, адресуются только к определенным
приемам, для обучения которым и создавалось это упражнение. Несущественные, несвязанные и слишком
сложные материалы не используются.
Там где это возможно, упражнения выполняются в Web. Однако упражнения, которые требуют доступа к
функциям Java или библиотечным функциям, способным вызвать нарушение безопасности, не выполняются
в Web.
Цели обучения:
• Познакомиться с UML-определением банковской системы
• Закончить исходный код Java для системных интерфейсов
Цели обучения:
• Научиться запускать RMI Registry как отдельный процесс
• Запустить сервер, поддерживающий удаленные объекты RMI
• Реализовать RMI-клиент, использующий удаленные службы
3. Параметры RMI
При вызове удаленного метода удаленному объекту могут быть переданы параметры, а
вызывающей программе – возвращаемое значение. В этом упражнении исследуется, как RMI
управляет передачей простых типов данных, локальных объектов Java и удаленных объектов RMI в
качестве параметров и возвращаемых значений.
Цели обучения:
• Попрактиковаться в определении и реализации удаленных интерфейсов
• Изучить, как удаленные объекты и нормальные объекты передаются в качестве параметров
Построить клиентские обратные вызовы с RMI очень легко. Можно просто создать на клиенте
удаленный объект и передать ссылку на него серверу. Сервер затем может использовать эту
удаленную ссылку для вызова методов в клиентской программе.
Цели обучения:
• Изучить, как создать удаленные объекты на клиенте
• Подготовить и экспортировать удаленные объекты, прямо не расширяющие интерфейс
java.rmi.server.UnicastRemoteObject
Сначала вы запустите сервер, который передает файлы классов Java по протоколу HTTP.
Затем вы создадите и запустите начальный загрузчик RMI-сервера. Этот сервер очень похож на
другие серверы, которые вы запускали. Главным его отличием в данном упражнении является то,
что код RMI-клиента находится в том же каталоге, что и сервер. Передача классов клиента на
клиентский компьютер является задачей HTTP-сервера.
Цели обучения:
• Рассмотреть классы поддержки HTTP-сервера для RMI-системы
• Рассмотреть, как написать простой HTTP-сервер
• Создать и запустить программу RMI-сервера
• Создать программу начальной загрузки клиентской программы по сети
• Запустить начальный загрузчик клиента и рассмотреть, как программа HTTP-сервера
сообщает о запрошенных и переданных классах
• Изучить системное свойство java.rmi.server.codebase
Цели обучения:
• Исследовать поведение распределенного сборщика мусора
• Исследовать взаимодействие распределенного и локального сборщиков мусора
• Поэкспериментировать с различными установками для кучи Java и отметить, как это влияет
на действия двух сборщиков мусора
Это упражнение показывает, как использовать модель делегирования для создания системы,
которая дает возможность сетевым службам мигрировать между локальной JVM и удаленным
сервером.
Это простая версия архитектуры делегирования. Более изощренные архитектуры могут быть
построены путем расширения этого примера.
Упражнение состоит из двух частей. Сначала запустите сервер, а затем клиент для выполнения
примера.
Цели обучения:
• Понять, как RMI ограничивает возможность перемещения удаленных объектов между JVM
• Посмотреть, как использовать модель делегирования для преодоления этих ограничений
Клиентская программа сделает запрос на обслуживание как удаленной ссылке так и локальной
копии объекта.
Цели обучения:
• Увидеть, как создается RMI-клиент, использующий либо удаленную ссылку для
обслуживания, либо локальную копию объекта, реализующего эту службу.
Скелетный код
Account.java
BankManager.java
Client.java
Задачи
1. Исследовать UML-диаграмму для банковской системы
Там, где существует файл помощи, номера вышеперечисленных задач ссылаются на страницу пошаговой
помощи.
После выполнения этого упражнения вы получите определения интерфейсов Java для трех удаленных служб
RMI.
Демонстрация
Никакого поведения еще не существует. Это упражнение включает только написание исходного кода.
Помощь
Помощь доступна для каждой задачи.
Задача 1
Исследовать UML-диаграмму для банковской системы.
Задача 2
Закончить исходный код для определения интерфейсов в этой системе.
Проверьте, что каждый интерфейс расширяет Remote и что каждый метод объявляет, что он может
создавать исключительную ситуацию RemoteException.
В этом упражнении вы запустите RMI Registry (который будет управлять публикацией удаленных служб
RMI), запустите программу сервера, создающую фактические удаленные службы и, наконец, завершите
кодирование программы BankUser, которая будет использовать эти удаленные службы RMI.
Предварительные условия
Пример UML-определения системы RMI
Скелетный код
Account.class
AccountImpl.class
AccountImpl_Stub.class
AccountImpl_Skel.class
BankManager.class
BankManagerImpl.class
BankManagerImpl_Stub.class
BankManagerImpl_Skel.class
Client.class
ClientImpl.class
ClientImpl_Stub.class
ClientImpl_Skel.class
NoCashAvailableException.class
BankSystemServer.class
BankUser.java
Задачи
1. Запустите программу RMI Registry.
Там, где существует файл помощи, номера вышеперечисленных задач ссылаются на страницу пошаговой
помощи.
Демонстрация
Когда запущены RMI Registry и RMI-сервер, нет никаких видимых признаков этого. Когда запущена
клиентская программа BankUser, на экране отобразится сообщение, которое вы включили в программу. В
данном случае отобразится следующее сообщение: Charlie's account has $600.00
Помощь
Помощь доступна для каждой задачи.
Задача 1
Запустите программу RMI Registry.
Программа RMI Registry поставляется как отдельный исполняемый файл rmiregistry. Создайте
консоль и перейдите в каталог, содержащий ваш исходный код из этого упражнения. Запустите реестр,
выполнив следующую команду:
rmiregistry
Задача 2
Скопируйте все .class–файлы в каталог.
Нажмите правую кнопку мыши на каждом файле для его сохранения. Исходные файлы предоставлены с
решением, на случай, если вы не захотите написать его самостоятельно.
Задача 3
Запустите RMI-сервер, который содержит удаленные объекты.
Это осуществляется путем создания новой консоли, переходом в каталог, содержащий код этого
упражнения и выполнением следующей команды: java BankSystemServer
Задача 4
Создайте и запустите программу, которая будет использовать экспортированные RMI-службы. Найдите
владельца счета 4461 и определите сумму денег на этом счету.
Завершите код для BankUser, используя в качестве ориентиров определения интерфейсов удаленных
служб. Затем откомпилируйте и запустите эту программу для проверки RMI-системы в действии.
Параметры RMI
В этом примере вы создадите RMI-службу, возвращающую два объекта клиенту. Как и в упражнении
«Простая банковская система» вам необходимо изменить константу HOST_NAME для приведения ее в
соответствие с сетевым именем вашего компьютера.
Вы также расширите интерфейс Hello и класс HelloImpl для передачи объекта Java MessageObject из
сервера клиенту.
Скелетный код
Hello.java
HelloImpl.java
MessageObject.java
RMIServer.java
RMIClient.java
Задачи
Там, где существует файл помощи, номера вышеперечисленных задач ссылаются на страницу пошаговой
помощи.
Демонстрация
Когда сервер запустится в своей DOS-консоли, отобразится следующая информация:
Так как на вашем компьютере исполняется и сервер и клиент, на экране отображается сообщения из
MessageObject. На консоли сервера отображается:
Когда экземпляр MessageObject перемещается между сервером и клиентом, две JVM загружают свои
собственные независимые копии файла класса. Переменная класса инкрементируется на сервере, но это
никак не отражается на клиенте.
Помощь
Помощь доступна для каждой задачи.
Задача 1
Добавьте метод getMessageObject в интерфейс Hello.
Задача 2
Создайте реализацию метода getMessageObject в классе HelloImpl.
Задача 3
Откомпилируйте все файлы классов для сервера и его удаленных объектов.
javac *.java
Задача 4
Создайте файлы заглушки и скелета для реализации удаленного объекта.
rmic HelloImpl
Задача 5
Запустите RMI-сервер в отдельной DOS-консоли.
Запустите новую DOS-консоль. Перейдите из текущего каталога в каталог, содержащий ваши .java-
файлы для сервера. Запустите RMIServer, используя программу java:
java RMIServer
Задача 6
Запустите RMI-клиент в отдельной DOS-консоли.
Запустите новую DOS-консоль. Перейдите из текущего каталога в каталог, содержащий ваши .java-
файлы для клиента. Запустите RMIClient, используя программу java:
java RMIClient
Для поддержки обратных вызовов, апплет должен действовать как RMI-сервер. Это осуществляется при
помощи экспорта и реализации удаленного интерфейса. Наш апплет определяет и реализует интерфейс
TimeMonitor. Он предназначен для вызова службой времени, обеспечивающей текущую дату и время.
Сервер не может сделать обратный вызов в апплет до тех пор, пока не узнает его расположение. Апплет
должен зарегистрировать себя на сервере. Он делает это при помощи метода сервера
registerTimeMonitor в TimeServer и передает ссылку на себя в интерфейс сервера.
В этом упражнении вам необходимо определить интерфейсы и реализации как для сервера, так и для
апплета.
Предварительные условия
Клиентские обратные вызовы RMI
Скелетный код
TimeMonitor.java
TimeServer.java
RMIServer.java
Applet1.java
Задачи
1. Определите и откомпилируйте интерфейс TimeMonitor
2. Определите и откомпилируйте интерфейс TimeServer
Там, где существует файл помощи, номера вышеперечисленных задач ссылаются на страницу пошаговой
помощи.
Демонстрация
Когда сервер запускается в DOS-консоли, отображается следующая информация:
Registry created
Bindings Finished
Waiting for Client requests
Апплет появится в окне и начнет отображать текущую дату и время каждые две секунды.
Помощь
Помощь доступна для каждой задачи.
Задача 1
Определите и откомпилируйте интерфейс TimeMonitor.
Создайте интерфейс TimeMonitor, имеющий один метод. Этот метод называется tellMeTheTime.
Он принимает один параметр типа Date и возвращает void.
Помните, что удаленные интерфейсы должны расширять java.rmi.Remote и все удаленные методы
могут генерировать java.rmi.RemoteException.
javac TimeMonitor.java
Задача 2
Определите и откомпилируйте интерфейс TimeServer.
Помните, что удаленные интерфейсы должны расширять java.rmi.Remote и все удаленные методы
могут генерировать java.rmi.RemoteException.
Задача 3
Закончите реализацию метода registerTimeMonitor в RMIServer.
Задача 4
Закончите определение класса TimeTicker.
Класс TimeTicker определяется внутри файла для RMIServer. Вам необходимо откомпилировать
реализацию этого класса, после добавления вызова метода tellMeTheTime интерфейса
TimeMonitor. В этом методе выполняется обратный вызов в апплет.
Задача 5
Откомпилируйте сервер, RMIServer и создайте файлы заглушки и скелета.
javac RMIServer
rmic RMIServer
Задача 6
Подготовьте апплет для исполнения.
Код апплета написан за вас. Вы должны исследовать его, чтобы понять, как реализуется интерфейс
TimeMonitor и как он подготавливает себя для использования в RMI с помощью вызова
UnicastRemoteObject.exportObject.
Прежде всего, вам необходимо откомпилировать его при помощи следующей команды:
javac Applet1.java
Далее, создайте файлы заглушки и скелета, используя программу rmic:
rmic Applet1
Задача 7
Запустите RMI-сервер в отдельной DOS-консоли.
java RMIServer
Задача 8
Запустите апплет при помощи appletviewer.
appletviewer Applet.html
Вы должны поместить файлы HTTP-сервера в подкаталог, отличный от каталога, содержащего файлы RMI-
сервера и клиента. После компиляции запустите HTTP-сервер из своего подкаталога и добавьте параметр
пути, который укажет HTTP-серверу переместить файлы классов из подкаталога RMI-сервера.
Затем вы создадите и запустите начальный загрузчик RMI-сервера. Этот сервер очень похож на другие
серверы, которые вы запускали. Главным его отличием в данном упражнении является то, что код RMI-
клиента находится в том же каталоге, что и код сервера. Обратите внимание, что все файлы уже созданы за
вас. Передача классов клиента на клиентский компьютер является задачей HTTP-сервера.
Одной из проблем создания загрузочной программы является передача начальной информации из нее в
фактический код клиента. Программа использует системное свойство для сохранения информации, которая
должна быть передана в фактическую клиентскую программу.
Обратите внимание, что в этом упражнении важно запускать программы в следующей последовательности:
Скелетный код
ClassServer.java
ClassFileServer.java
runhttp.bat
MessageObject.java
Hello.java
RMIServer.java
HelloImpl.java
runserver.bat
RMIClient.java
RMIClientBootstrapSecurityManager.java
RMIClientLoader.java
runclient.bat
Задачи
1. Сохраните два файла программы и командный файл runhttp.bat в какой-нибудь каталог и
откомпилируйте файлы HTTP-сервера
2. Запустите HTTP-сервер
Там, где существует файл помощи, номера вышеперечисленных задач ссылаются на страницу пошаговой
помощи.
Демонстрация
Когда HTTP-сервер запускается в DOS-консоли, отображается следующая информация:
ClassFileServer started...
Когда клиент запускается и загружает файлы из HTTP-сервера, обратите внимание, что HTTP-сервер
отображает файлы, которые он читает с диска. Первая программа, которую он передает, представляет собой
собственно клиентскую программу RMIClient. После этого, он передает файлы заглушки и другие файлы
классов, необходимые для работы клиента.
Наконец, когда клиентская программа начальной загрузки выполняется в своей консоли, отображается
следующая информация:
http://ROSA:2002/
After loading Client Class
Message from Server: Hello!
MessageObject: Class Number is #0 Object Number is #0
MessageObject: Class Number is #0 Object Number is #1
MessageObject: Class Number is #0 Object Number is #2
MessageObject: Class Number is #0 Object Number is #3
MessageObject: Class Number is #0 Object Number is #4
MessageObject: Class Number is #0 Object Number is #5
MessageObject: Class Number is #0 Object Number is #6
MessageObject: Class Number is #0 Object Number is #7
MessageObject: Class Number is #0 Object Number is #8
MessageObject: Class Number is #0 Object Number is #9
Помощь
Помощь доступна для каждой задачи.
Задача 1
Сохраните два файла программы и командный файл runhttp.bat в какой-нибудь каталог и
откомпилируйте файлы HTTP-сервера.
javac ClassServer.java
javac ClassFileServer.java
Задача 2
Запустите HTTP-сервер
Создайте новое консольное окно и перейдите в каталог, содержащий откомпилированные классы. Когда
вы запускаете HTTP-сервер, вы передаете ему два параметра. Первый – это номер порта, который он
прослушивает. Второй – это путь к каталогу, содержащему файлы классов RMI, предназначенные для
передачи по сети.
Задача 3
Откомпилируйте все файлы классов для клиента и сервера
javac MessageObject.java
javac Hello.java
javac RMIServer.java
javac HelloImpl.java
javac RMIClient.java
Таким образом компилируется сервер и все классы клиента, которые впоследствии будут загружаться
начальным загрузчиком по сети.
Задача 4
Создайте файлы заглушки и скелета для реализации удаленного объекта
rmic HelloImpl
Задача 5
Запустите программу RMI-сервера
Командный (пакетный) файл runserver.bat создан для того, чтобы помочь вам запустить RMI-
сервер. Отредактируйте этот файл и запишите в него корректную информацию для вашего компьютера,
а затем запустите сервер в отдельном консольном окне.
Задача 6
Откомпилируйте файлы классов для программы начальной загрузки
В отдельном консольном окне сохраните файлы клиентской программы начальной загрузки и запустите
командный файл runclient.bat в отдельном подкаталоге, скомпилируйте исходные .java-файлы:
javac RMIClientBootstrapSecurityManager.java
javac RMIServer.java
Единственной целью программы начальной загрузки является запуск и затем запрос «реальной»
клиентской программы по сети.
Задача 7
Отредактируйте командный файл runclient.bat, включив имя вашего компьютера
Измените имя «ROSA» на имя вашего компьютера. Командный файл будет готов к запуску.
Задача 8
Запустите командный файл runclient.bat.
В этом упражнении не требуется писать код, но вы должны изменить значение константы HOST_NAME на
соответствующее имя вашего компьютера. Вам также следует посмотреть на код классов этого примера,
особенно MessageObjectImpl, для того, чтобы понять, как он работает.
Упражнение содержит два удаленных объекта: Hello и MessageObject. Их реализации разработаны для
того, чтобы вывести сообщения при их создании, удалении ссылок на них, финализации и уничтожении.
Удаленный объект может реализовать интерфейс Unreferenced и его метод unreferenced. Этот метод
вызывается DGC во время удаления им последней ссылки на объект. MessageObjectImpl и HelloImpl
разработаны так, что выводят сообщение об этой ситуации.
Материалы курса для этого упражнения рассмотрены в разделе «Распределенный сборщик мусора».
При запуске упражнения вы, возможно, захотите поэкспериментировать с установками размера кучи Java
(используйте аргумент командной строки – mx) и явно установить значение leaseValue для удаленных
ссылок DGC. Для этого используйте следующую командную строку:
Скелетный код
Hello.java
HelloImpl.java
MessageObject.java
MessageObjectImpl.java
RMIServer.java
RMIClient.java
Задачи
1. Измените значение константы HOST_NAME в RMIClient.java и RMIServer.java на
соответствующее имя вашего компьютера
Демонстрация
Когда сервер запускается в DOS-консоли, отображается следующая информация:
Исследуйте, как консоль сервера отображает процесс работы GDC и локального сборщика мусора.
Помощь
Помощь доступна для каждой задачи.
Задача 1
Измените значение константы HOST_NAME в RMIClient.java и RMIServer.java на
соответствующее имя вашего компьютера.
Задача 2
Откомпилируйте все исходные Java-файлы.
javac *.java
Задача 3
Из подкаталога Solution запустите сервер RMIServer с наименьшим возможным размером кучи.
Задача 4
java RMIClient
Когда готовы обе консоли, нажмите клавишу «Enter» в обеих, так чтобы запустить программу примерно
в одно и то же время.
Заметьте, что локальный сборщик мусора не уничтожает объекты сразу, как только они закончили свою
работу. Вы также можете заметить, что после завершения демонстрации сервер полностью освобождает
все объекты примерно через 10 минут. Это указывает на то, что срок аренды этих удаленных объектов
был установлен в значение 10 минут. Так как клиенты завершили свою работу, сервер будет ждать
окончания срока аренды перед переводом объектов в состояние «чистый».
В этом упражнении вы увидите, как используется модель делегирования для разрешения миграции службы.
Эта тема описана в разделе «Cериализация удаленных объектов».
Скелетный код
RemoteModelMgr.java
RemoteModelMgrImpl.java
RemoteModelImpl.java
LocalRemoteServer.java
LocalModel.java
RemoteModelRef.java
Задачи
1. Откомпилируйте все файлы классов сервера
Там, где существует файл помощи, номера вышеперечисленных задач ссылаются на страницу пошаговой
помощи.
После окончания этого упражнения перейдите к следующему для выполнения данного проекта.
Исходные коды решения
RemoteModelMgr.java
RemoteModelMgrImpl.java
RemoteModelImpl.java
LocalRemoteServer.java
LocalModel.java
RemoteModelRef.java
Демонстрация
Когда сервер запускается в DOS-консоли, отображается следующая информация:
Помощь
Помощь доступна для каждой задачи.
Задача 1
Откомпилируйте все файлы классов сервера.
В отдельной DOS-консоли перейдите в подкаталог server для этого примера. Откомпилируйте все java-
файлы, используя команду:
javac *.java
Она откомпилирует файлы сервера и все классы клиентов, которые будут загружаться по сети.
Задача 2
Создайте файлы заглушки и скелета для реализации удаленного объекта.
rmic RemoteModelMgrImpl
rmic RemoteModelImpl
Задача 3
Запустите программу RMI-сервера.
java LocalRemoteServer
В этом упражнении вы увидите, как используется модель делегирования для разрешения миграции службы.
Эта тема описана в разделе «Cериализация удаленных объектов».
Скелетный код
LocalRemoteClient.java
Задачи
1. Переместите файлы заглушек из подкаталога Server
Там, где существует файл помощи, номера вышеперечисленных задач ссылаются на страницу пошаговой
помощи.
Демонстрация
Когда клиент запускается в DOS-консоли, отображается следующая информация:
Помощь
Помощь доступна для каждой задачи.
Задача 1
Переместите файлы заглушек из подкаталога Server.
LocalModel.class
RemoteModelMgrImpl_Stub.class
RemoteModelImpl_Stub.class
RemoteModelRef.class
RemoteModelMgr.class
Задача 2
Откомпилируйте все файлы классов для клиента.
В отдельной DOS-консоли перейдите в подкаталог Client для этого примера. Откомпилируйте все java-
файлы, используя команду:
javac *.java
Она откомпилирует все клиентские классы.
Задача 3
Запустите клиентскую программу RMI.
java LocalRemoteClient