Плохая идея связать исключения цепочкой с RMI?

StackOverflow https://stackoverflow.com/questions/351205

  •  20-08-2019
  •  | 
  •  

Вопрос

Плохая ли идея использовать цепочку исключений при выбрасывании RemoteExceptions?У нас есть сервер RMI, который делает что-то вроде этого:

public Object doSomething() throws RemoteException
{
    try
    {
        return getData();
    }
    catch (CustomException ex)
    {
        throw new RemoteException(ex);
    }
}

Я получаю исключение UnmarshallException, вызванное ClassNotFoundException в моем клиенте.С положительной стороны, оказывается, что экспортируется само CustomException.К сожалению, другое исключение глубоко внутри этого парня НЕ экспортируется, и именно здесь возникает ClassNotFoundException .Я думаю, что иерархия выглядит примерно так:

RemoteException -> CustomException -> SQLException -> NotExportedException

Проблема, которую я вижу, заключается в том, что, хотя мы можем гарантировать, что CustomException экспортируется, мы не можем гарантировать, что экспортируются какие-либо исключения более низкого уровня.

Из-за этого я склоняюсь к ТОМУ, чтобы НИКОГДА НЕ использовать цепочку исключений с RemoteExceptions.Вместо этого, я думаю, мне, вероятно, следует зарегистрировать трассировку стека на стороне сервера и выдать простое ванильное исключение RemoteException без привязки к нему исключения "причина".Кто-нибудь сталкивался с такой ситуацией раньше?

Это было полезно?

Решение

Вместо того чтобы оборачивать CustomException в RemoteException, вы могли бы изменить свой удаленный интерфейс следующим образом:

interface Foo extends Remote {

  Object doSomething() throws CustomException, RemoteException;

}

Принцип здесь заключается в том, что только среда выполнения RMI должна вызывать RemoteExceptions;они сигнализируют о каком-то сбое в удаленном взаимодействии, а не в логике приложения.Фактически, конкретным реализациям даже не нужно объявлять RemoteException.

Но это не относится к случаю, когда ваш сервис перехватывает исключение из какой-либо сторонней библиотеки, но не хочет раскрывать это в предложении throws .

public Object doSomething() throws CustomException {
  try {
    return theirSvc.getData();
  } catch (ThirdPartyException ex) {
    throw new CustomException("Failed to obtain requested data.");
    // or: throw new CustomException("Failed to obtain requested data.", ex) ?
  }
}

В этом случае я рекомендую вам не создавать "дырявую абстракцию", где зависимость создавалась бы в клиенте, которому в противном случае не было бы необходимости знать об этой сторонней библиотеке.

Обычно ведение журнала и выбрасывание - плохая практика, потому что одна и та же ошибка регистрируется повторно.Но в данном случае, я думаю, это оправдано, поскольку сгенерированное исключение передается клиенту;может быть полезно зарегистрировать его как на клиенте, так и на сервере.Таким образом, блок catch в конечном итоге выглядит следующим образом:

catch (ThirdPartyException ex) {
   String message = "Failed to obtain requested data.";
   log.error(message, ex);
   throw new CustomException(message);
 }

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

Другие советы

Мы фиксируем сообщение + трассировку всего стека из исходного исключения и передаем это как содержимое удаленного исключения.Таким образом, вы получаете все сведения о стеке, но вам не нужно беспокоиться о том, что какое-либо из внутренних исключений не является сериализуемым.

Вы никогда не знаете, какие другие объекты могут находиться внутри какой-либо другой третьей стороны (или даже ваших собственных пользовательских исключений "первой стороны"!).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top