Удаленный вызов методов (RMI)


Традиционный подход к выполнению кода на других машинах, разнесенных по сети может смутить из-за своей нудной и склонной к ошибкам реализации. Лучший способ рассмотреть эту проблему состоит в предположении, что некоторые объекты располагаются на другой машине, и что вы можете посылать сообщения этим удаленным объектам и получать результат, как будто они располагаются на вашей локальной машине. Это упрощение в точности является тем, что позволяет делать Удаленный Вызов Методов (RMI) в Java. Этот раздел сделает обзор шагов, необходимых для создания вашего собственного RMI объекта.

Удаленный интерфейс

RMI делает тяжелым использование интерфейсов. Когда вы хотите создать удаленный объект, вы маскируете лежащую в основе реализацию, общаясь по интерфейсу. То есть, когда клиент получает ссылку на удаленный объект, реально он получает ссылку на интерфейс, который соединен с некоторым локальным кодом заглушки, которая общается по сети. Но вы не думаете об этом, вы просто посылаете сообщения через вашу ссылку на интерфейс.

Когда вы создаете удаленный интерфейс, вы должны следовать следующему руководству:

  • Удаленный интерфейс должен быть публичным (он не может иметь "пакетный уровень доступа", таким образом он не может быть "дружественным"). В противном случае, клиент получит ошибку при попытке загрузить удаленный объект, который реализует удаленный интерфейс.
  • Удаленный интерфейс должен наследоваться от интерфейса java.rmi.Remote.
  • Каждый метод удаленного интерфейса должен декларировать java.rmi.RemoteException в своем разделе throws в дополнение ко всем остальным специфичным для приложения исключениям.
  • Удаленный объект, передающийся как аргумент или возвращаемое значение (либо напрямую, либо как встроенная часть локального объекта), должен быть декларирован как удаленный интерфейс, а не класс реализации.

Вот простейший удаленный интерфейс, который представляет службу точного времени:

//: c15:rmi:PerfectTimeI.java
// The PerfectTime remote interface.
package c15.rmi;

import java.rmi.*;

public interface PerfectTimeI extends Remote {
  
long getPerfectTime() throws RemoteException;
} // /:~

Он выглядит как и любой другой интерфейс, за исключением того, что он является наследником Remote и все его методы выбрасывают RemoteException. Помните, что все методы интерфейса автоматически являются публичными.

Реализация удаленного интерфейса

Сервер должен содержать класс, который наследуется от UnicastRemoteObject и реализует удаленный интерфейс. Этот класс может также иметь дополнительные методы, но для клиента, конечно, будут доступны только методы удаленного интерфейса, так как клиент будет получать только ссылку на интерфейс, а не на класс, реализующий его.

Вы должны явно определить конструктор для удаленного объекта, даже если вы определяете только конструктор по умолчанию, который вызывает конструктор базового класса. Вы должны написать его, так как он должен выбрасывать RemoteException.

Вот реализация удаленного интерфейса PerfectTimeI:

//: c15:rmi:PerfectTime.java
// Реализация удаленного
// объекта PerfectTime.
// {Broken}
package c15.rmi;

import java.rmi.*;

import java.rmi.server.*;

import java.rmi.registry.*;

import java.net.*;

public class PerfectTime extends UnicastRemoteObject implements PerfectTimeI {
  
// Реализация интерфейса:
  
public long getPerfectTime() throws RemoteException {
     
return System.currentTimeMillis();
  
}
  
  
// Необходимо реализовывать конструктор,
   // выбрасывающий RemoteException:
  
public PerfectTime() throws RemoteException {
     
// super(); // Вызывается автоматически
  
}
  
  
// Регистрация для обслуживания RMI. Выбрасывает
   // исключения на консоль.
  
public static void main(String[] args) throws Exception {
     
System.setSecurityManager(new RMISecurityManager());
      PerfectTime pt =
new PerfectTime();
      Naming.bind
("//peppy:2005/PerfectTime", pt);
      System.out.println
("Ready to do time");
  
}
}
// /:~

Здесь main( ) обрабатывает все детали установки сервера. Когда вы обслуживаете RMI объекты, в некотором месте вашей программы вы должны:

  • Создать и установить менеджер безопасности, который поддерживает RMI. Для RMI досупен только один такой менеджер, как часть пакета Java, он называется RMISecurityManager.
  • Создать один или несколько экземпляров удаленного объекта. Здесы вы можете видеть создание объекта PerfectTime.
  • Зарегистрировать как минимум один удаленный объект в RMI репозитории удаленных объектов в целях загрузки. Один удаленный объект может иметь методы, которые производят ссылки на другие удаленные объекты. Это позволит вам сделать так, чтобы клиент обращался к репозиторию только один раз, чтобы получить первый удаленный объект.

Настройка репозитория