RMI (JDK 1.6): ClassNotFoundException для <server>_Stub в клиентском приложении - PullRequest
0 голосов
/ 17 мая 2011

После 2 дней поиска, поиска в стеке и поиска ответов на других форумах я, наконец, сдался и надеюсь найти ответ здесь!

У меня раздражающая проблема в получении простого клиента RMI-серверное приложение для запуска, хотя кажется (или, может быть, мне просто не хватает чуть-чуть) известной проблемы с RMI.

Я использую Eclipse и m2eclipse (интеграция Maven) для управления зависимостями.Моя структура проекта выглядит следующим образом: - клиент: код клиента, зависимость от общего - сервер: код сервера, зависимость от общего - общий: удаленные интерфейсы и общие классы между сервером и клиентом - интеграция тест: тестовый проект, имеющий обе зависимости от клиента иserver

Shared:

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

public interface IServerReceiver extends Remote, Serializable {
  void connect(long clientId) throws RemoteException;
}

Этот интерфейс находится в общем проекте, где и клиент, и сервер зависят от so он находится в classpath клиента .

На стороне сервера:

Класс Server отвечает за создание реестра и экспорт удаленного объекта (ServerReceiver реализует IServerReceiver):

registry = LocateRegistry.createRegistry(rmiRegistryPort);
serverReceiver = new ServerReceiver(rmiRegistryPort);

registry.rebind(IConstants.RMI_SERVER_RECEIVER_ID, UnicastRemoteObject.exportObject(serverReceiver, 0));

При запуске сервера файл политики безопасности предоставляется JVM сервера путем определения -Djava.security.policy (хотя я не думаю, что это связано с проблемой, описанной здесь).

Клиентская сторона

Класс, отвечающий за подключение клиента к серверу, - это ServerConnector class:

...
public ServerConnector() {
 ...
 registry = LocateRegistry.getRegistry(serverRMIHost, serverRMIPort);
 serverReceiver = (IServerReceiver) registry.lookup(IConstants.RMI_SERVER_RECEIVER_ID);
 serverReceiver.connect(client.getId());
 ...
}

Конструктор класса клиента выглядит следующим образом (некоторые строки опущены):

public Client(..) {
 ....
 serverConnector = new ServerConnector(serverRMIHost, serverRMIPort, this);
 ....
}

Как и сервер, клиент также получает файл политики безопасности.

Тестирование

Когда я запускаю интеграционный тест, создавая сервер, а затем клиента: все работает нормально, как ожидалось, и метод connect () возвращает ожидаемый результат.

Однако, когда я пытаюсь нормально запустить экземпляр сервера, а затем запустить экземпляр клиента, который пытается подключиться () к серверу, выдается следующее исключение:

Caused by: java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
java.lang.ClassNotFoundException: assign2.comm.ServerReceiver_Stub
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at assign2.comm.ServerConnector.<init>(ServerConnector.java:65)

При поиске ответов наиболееВидным было: клиент должен иметь доступ к определению интерфейса сервера (IServerReceiver).Тем не менее, мне кажется, что это так и есть, поскольку надлежащие зависимости на месте (клиент-> общий, сервер-> общий, IServerReceiver место в общем).Еще один аспект исключения, которого я не совсем понимаю: начиная с JDK 1.5, создание заглушек через rmic больше не требуется и достигается с помощью динамических прокси.Поэтому клиенту необходим только доступ к интерфейсу IServerReceiver для создания динамического прокси.Почему тогда он будет жаловаться на то, что вообще не найдет класс ServerReceiver_Stub?

Поскольку интеграционный тест выполняется успешно, и в рамках этого теста клиент также имеет доступ к реализации интерфейса IServerReceiver,Правильно ли я полагаю, что клиенту нужен не только доступ к удаленному интерфейсу, но и его реализация?

Сейчас я немного растерялся, так что, может быть, вы можете помочь мне пролить свет на этот вопрос?Спасибо, что прочитали этот длинный пост!; -)

Ура, Крис

Ответы [ 2 ]

1 голос
/ 17 мая 2011

IServerReceiver должно не быть Serializable.я предполагаю, что ваш экземпляр сервера отправляется по сети, а не через прокси.

1 голос
/ 17 мая 2011

Согласен, заглушка вам не нужна, так как вы предоставляете номер порта при экспорте объекта.Единственное объяснение состоит в том, что сгенерированная заглушка стала связанной вместо динамической заглушки.Я бы удалил любые существующие файлы-заглушки и перепроверил.Если серверу нужна заглушка, а у него его нет, он должен выйти из строя во время экспорта, а не когда кто-то ищет его.

Прав ли я, полагая, что клиенту нужен не только доступ к удаленномуинтерфейс, но и его реализация?

Нет.Нужна только заглушка.Реализация удаленная.Вот и вся идея.Но ему также нужны все классы, от которых зависит заглушка, то есть удаленный интерфейс и любые классы, от которых зависит и т. Д. До закрытия.

У меня есть еще вопросы:

  1. Почему порт реестра предоставляется новому ServerReceiver (rmiRegistryPort)?
  2. Я предполагаю, что ServerReceiver не расширяет UnicastRemoteObject?
  3. Вы уверены, что это настоящий код серверачто исполняется?
...