После 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,Правильно ли я полагаю, что клиенту нужен не только доступ к удаленному интерфейсу, но и его реализация?
Сейчас я немного растерялся, так что, может быть, вы можете помочь мне пролить свет на этот вопрос?Спасибо, что прочитали этот длинный пост!; -)
Ура, Крис