用RMI链接exception的坏主意?

抛出RemoteExceptions时使用exception链接是一个坏主意吗? 我们有一个RMI服务器,它执行以下操作:

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

我在客户端中遇到由ClassNotFoundException引起的UnmarshallException。 从好的方面来看,事实certificateCustomException本身是导出的。 不幸的是,这个人内部的另一个exception是没有导出,这是ClassNotFoundException的来源。我认为层次结构是这样的:

RemoteException – > CustomException – > SQLException – > NotExportedException

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

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

您可以修改远程接口,而不是将RemoteException包装在RemoteException中:

 interface Foo extends Remote { Object doSomething() throws CustomException, RemoteException; } 

这里的原则是只有RMI运行时应该引发RemoteExceptions; 它们表示远程处理有些失败,而不是应用程序逻辑。 实际上,具体实现甚至不需要声明RemoteException

但是,这不处理您的服务从某些第三方库捕获exception但不希望在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) ? } } 

在这种情况下,我建议您不要创建“漏洞抽象”,其中将在客户端中创建依赖关系,否则无需了解该第三方库。

通常,记录抛出是不好的做法,因为重复记录相同的错误。 但在这种情况下,我认为这是合理的,因为抛出的exception被传递给客户端; 在客户端和服务器上记录它可能很有用。 所以catch块最终看起来像这样:

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

这样,ThirdPartyException依赖关系仅限于服务器,服务器日志包含适当的特定于实现的信息,并且错误被正确地报告给客户端。

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

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