Spec-Zone .ru
спецификации, руководства, описания, API
|
Это учебное руководство показывает Вам шаги, чтобы следовать, чтобы создать распределенную версию классики Привет Мировая программа, используя Java™ Удаленный Вызов метода (Java RMI). В то время как Вы работаете через этот пример, Вы, вероятно, придумаете много связанных вопросов. Можно счесть ответы в Java FAQ RMI.
Распределенный Привет Мировой пример использует простой клиент, чтобы сделать удаленный вызов метода к серверу, который может работать на удаленном узле. Клиент получает "Привет, мир!" сообщение от сервера.
У этого учебного руководства есть следующие шаги:
Hello.java
- удаленный интерфейсServer.java
- реализация удаленного объекта, которая реализует удаленный интерфейсClient.java
- простой клиент, который вызывает метод удаленного интерфейсаexample.hello.Server
, который реализует удаленный интерфейс. java.rmi.Remote
и объявляет ряд удаленных методов. Каждый удаленный метод должен объявить java.rmi.RemoteException
(или суперкласс RemoteException
) в throws
пункт, в дополнение к любым специализированным исключениям. Вот определение интерфейса для удаленного интерфейса, используемого в этом примере, example.hello.Hello
. Это объявляет только один метод, sayHello
, который возвращает строку вызывающей стороне:
package example.hello; import java.rmi.Remote; import java.rmi.RemoteException; public interface Hello extends Remote { String sayHello() throws RemoteException; }Удаленные вызовы метода могут перестать работать многими дополнительными способами по сравнению с локальными вызовами метода (такими как связанные с сетью проблемы коммуникации и проблемы сервера), и отдалить методы, сообщат такие отказы, бросая a
java.rmi.RemoteException
. Для получения дополнительной информации о проблемах отказа и восстановления в распределенных системах, см. main
метод, который создает экземпляр реализации удаленного объекта, экспортирует удаленный объект, и затем связывает тот экземпляр с именем в Java реестр RMI. class, который содержит это main
метод мог быть реализацией class непосредственно, или другой class полностью. В этом примере, main
метод для сервера определяется в class Server
который также реализует удаленный интерфейс Hello
. Сервер main
метод делает следующее:
Server
. Описания для того, чтобы записать этому серверу class следуют за исходным кодом: package example.hello; import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class Server implements Hello { public Server() {} public String sayHello() { return "Hello, world!"; } public static void main(String args[]) { try { Server obj = new Server(); Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0); // Bind the remote object's stub in the registry Registry registry = LocateRegistry.getRegistry(); registry.bind("Hello", stub); System.err.println("Server ready"); } catch (Exception e) { System.err.println("Server exception: " + e.toString()); e.printStackTrace(); } } }
Реализация class Server
реализует удаленный интерфейс Hello
, обеспечение реализации для удаленного метода sayHello
. Метод sayHello
не должен объявить, что это выдает любое исключение, потому что реализация самого метода не бросает RemoteException
и при этом это не выдает никакие другие проверенные исключения.
Отметьте: class может определить методы, не определенные в удаленном интерфейсе, но те методы могут только быть вызваны в пределах виртуальной машины, выполняющей службу, и не могут быть вызваны удаленно.
main
метод сервера должен создать удаленный объект, который предоставляет услугу. Дополнительно, удаленный объект должен быть экспортирован в Java время выполнения RMI так, чтобы это могло получить входящие удаленные вызовы. Это может быть сделано следующим образом: Server obj = new Server(); Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);Статический метод
UnicastRemoteObject.exportObject
экспортирует предоставленный удаленный объект, чтобы получить входящие удаленные вызовы метода на анонимном порту TCP и возвращает тупик для удаленного объекта, чтобы передать клиентам. В результате exportObject
вызовите, время выполнения может начать слушать на новом сокете сервера или может использовать совместно используемый сокет сервера, чтобы принять входящие удаленные призывы к удаленному объекту. Возвращенный тупик реализует тот же самый набор удаленных интерфейсов как class удаленного объекта и содержит имя хоста и порт, по которому можно связаться с удаленным объектом. Отметьте: С J2SE 5.0 выпусков тупиковые классы для удаленных объектов больше не должны быть предварительно сгенерированы, используя rmic
тупиковый компилятор, если удаленный объект не должен поддерживать клиенты, работающие в пред5.0 VMs. Если Ваше приложение должно поддерживать такие клиенты, Вы должны будете генерировать тупиковые классы для удаленных объектов, используемых в приложении, и развернуть те тупиковые классы для клиентов, чтобы загрузить. Для получения дополнительной информации на том, как генерировать тупиковые классы, см. документацию инструментов для rmic
[Солярис, Windows]. Для получения дополнительной информации на том, как развернуть Ваше приложение наряду с предварительно сгенерированными тупиковыми классами, см. учебное руководство по кодовой базе.
Для вызывающей стороны (клиент, коллега, или апплет), чтобы быть в состоянии вызвать метод на удаленный объект, та вызывающая сторона должна сначала получить тупик для удаленного объекта. Для начальной загрузки Java RMI обеспечивает API реестра для приложений, чтобы обязать имя к тупику удаленного объекта и для клиентов искать удаленные объекты по имени, чтобы получить их тупики.
Реестр RMI Java является упрощенной службой имен, которая позволяет клиентам получать ссылку (тупик) к удаленному объекту. Вообще, реестр используется (если вообще) только, чтобы определить местоположение первого удаленного объекта, который должен использовать клиент. Затем, обычно, тот первый объект поочередно оказал бы специализированную поддержку для того, чтобы найти другие объекты. Например, ссылка может быть получена в качестве параметра к, или возвращаемое значение от, другой удаленный вызов метода. Для обсуждения на том, как это работает, пожалуйста смотрите на Применение Шаблона "фабрика" к Java RMI.
Как только удаленный объект регистрируется на сервере, вызывающие стороны могут искать объект по имени, получить ссылку удаленного объекта, и затем вызвать удаленные методы на объект.
Следующий код в сервере получает тупик для реестра на локальном узле и порту реестра значения по умолчанию и затем использует тупик реестра, чтобы связать имя "Привет" к тупику удаленного объекта в том реестре:
Registry registry = LocateRegistry.getRegistry(); registry.bind("Hello", stub);Статический метод
LocateRegistry.getRegistry
это не берет возвратов параметров тупик, который реализует удаленный интерфейс java.rmi.registry.Registry
и отправляет вызовы реестру на локальном узле сервера на порту реестра значения по умолчанию 1099
. bind
метод тогда вызывается на registry
тупик, чтобы связать тупик удаленного объекта с именем"Hello"
в реестре. Отметьте: звонок LocateRegistry.getRegistry
просто возвращает соответствующий тупик для реестра. Вызов не проверяет, чтобы видеть, работает ли реестр фактически. Если никакой реестр не работает на порту TCP 1099 из локального узла когда bind
метод вызывается, сервер перестанет работать с a RemoteException
.
Клиентская программа получает тупик для реестра на узле сервера, ищет тупик удаленного объекта по имени в реестре, и затем вызывает sayHello
метод на удаленном объекте, используя тупик.
Вот исходный код для клиента:
package example.hello; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class Client { private Client() {} public static void main(String[] args) { String host = (args.length < 1) ? null : args[0]; try { Registry registry = LocateRegistry.getRegistry(host); Hello stub = (Hello) registry.lookup("Hello"); String response = stub.sayHello(); System.out.println("response: " + response); } catch (Exception e) { System.err.println("Client exception: " + e.toString()); e.printStackTrace(); } } }
Этот клиент сначала получает тупик для реестра, вызывая помехи LocateRegistry.getRegistry
метод с именем узла, определенным на командной строке. Если никакое имя узла не определяется, то null
используется в качестве имени узла, указывающего, что локальный адрес узла должен использоваться.
Затем, клиент вызывает удаленный метод lookup
на тупике реестра, чтобы получить тупик для удаленного объекта от реестра сервера.
Наконец, клиент вызывает sayHello
метод на тупике удаленного объекта, который заставляет следующие действия происходить:
Сообщение ответа, возвращенное из удаленного вызова на удаленном объекте, тогда печатается к System.out
.
Исходные файлы для этого примера могут быть скомпилированы следующим образом:
javac -d destDir Hello.java Server.java Client.javaгде destDir является целевым каталогом, чтобы вставить файлы class.
Отметьте: Если сервер должен поддерживать клиенты, работающие на пред5.0 VMs, то тупиковый class для реализации удаленного объекта class должен быть предварительно сгенерирован, используя rmic
компилятор, и что тупиковый class должен быть сделан доступным для клиентов, чтобы загрузить. См. учебное руководство по кодовой базе для большего количества деталей.
Чтобы выполнить этот пример, Вы должны будете сделать следующее:
Чтобы запустить реестр, работайте rmiregistry
команда на узле сервера. Эта команда не производит вывода (когда успешный), и обычно выполняется в фоновом режиме. Для получения дополнительной информации см. документацию инструментов для rmiregistry
[Солярис, Windows].
Например, на Солярисе (ТМ) Операционная система:
rmiregistry &
Или, на платформах Windows:
start rmiregistry
По умолчанию реестр работает на порту TCP 1099. Чтобы запустить реестр на различном порту, определите номер порта из командной строки. Например, чтобы запустить реестр на порту 2001 на платформе Windows:
start rmiregistry 2001
Если реестр будет работать на порту кроме 1099, Вы должны будете определить номер порта в звонках LocateRegistry.getRegistry
в Server
и Client
классы. Например, если реестр работает на порту 2001 в этом примере, звонке getRegistry
в сервере был бы:
Registry registry = LocateRegistry.getRegistry(2001);
Чтобы запустить сервер, работайте Server
class используя java
команда следующим образом:
На Операционной системе Соляриса:
java -classpath classDir -Djava.rmi.server.codebase=file:classDir/ example.hello.Server &
На платформах Windows:
start java -classpath classDir -Djava.rmi.server.codebase=file:classDir/ example.hello.Server
где classDir является корневым каталогом дерева файла class. Установка java.rmi.server.codebase
системное свойство гарантирует, что реестр может загрузиться, удаленное определение интерфейса (отметьте, что запаздывающая наклонная черта важна); для получения дополнительной информации об использовании этого свойства, см. учебное руководство по кодовой базе.
Вывод от сервера должен быть похожим на это:
Server ready
Сервер остается работать, пока процесс не завершается пользователем (обычно, уничтожая процесс).
Как только сервер готов, клиент может быть выполнен следующим образом:
java -classpath classDir example.hello.Client
где classDir является корневым каталогом дерева файла class.
Вывод от клиента является следующим сообщением:
response: Hello, world!