用RMI链接异常的坏主意?

时间:2008-12-08 22:37:42

标签: java exception-handling rmi

在抛出RemoteExceptions时使用异常链接是一个坏主意吗?我们有一个RMI服务器,它可以做这样的事情:

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

我的客户端遇到ClassNotFoundException导致的UnmarshallException。从好的方面来看,事实证明CustomException本身是导出的。不幸的是,这个人内部的另一个异常是没有导出,这是ClassNotFoundException的来源。我认为层次结构是这样的:

RemoteException - > CustomException - > SQLException - > NotExportedException

我看到的问题是,即使我们可以保证导出CustomException,我们也无法保证任何较低级别的异常。

由于这个原因,我倾向于永远不要使用RemoteExceptions进行异常链接。相反,我认为我应该在服务器端记录堆栈跟踪并抛出一个简单的vanilla RemoteException,并没有链接到它的“cause”异常。有人之前处理过这种情况吗?

2 个答案:

答案 0 :(得分:5)

您可以修改远程接口,而不是将RemoteException包装在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依赖项仅限于服务器,服务器日志包含适当的特定于实现的信息,并且错误已正确报告给客户端。

答案 1 :(得分:3)

我们从源异常中捕获消息+整个堆栈跟踪,并将其作为远程异常的内容传递给它。这样您就可以获得所有堆栈详细信息,但您不必担心任何内部异常都是不可序列化的。

你永远不知道其他第三方内部可能有什么其他对象(甚至是你自己的“第一方”自定义异常!)