我使用RMI进行简单的客户端 - 服务器应用程序。服务器端应该生成某种PDF(itext)文件,客户端应该显示它。
尝试通过调用我自己的公共远程接口的正确方法在服务器端生成我的pdf时,客户端会抛出ClassNotFoundException
。
Caused by: java.lang.ClassNotFoundException: com.itextpdf.text.ExceptionConverter (no security manager: RMI class loader disabled)
我想,使用RMI就像使用黑盒子 - 客户端调用方法,并接收响应,而不知道如何完成,双方唯一的共同类是远程接口。更多的我认为这将允许我将客户端所需的依赖项缩减到最小。
客户端是否真的必须让其类路径中的所有服务器库都能正常工作?
编辑: 另一个奇怪的事实是,没有例外,并且在服务器端登录。 如果我将服务器端项目添加为客户端的依赖项,那么一切正常。
答案 0 :(得分:0)
这里只是一个猜测,它可能无法在服务器端正常捕获和处理ExceptionConverter
并且它正在传播到没有定义的客户端。
答案 1 :(得分:0)
如果您启用了RMI-classloader并设置了相应的系统属性(google for:“java.rmi.server.codebase”),那么RMI会将缺少的类从服务器动态加载到客户端 - 您的问题就会消失。无需在客户端存储和静态链接服务器库。
据我所知,RMI-classloader tutorial详细描述了这一点。
编辑:
我已经给出了动态类加载的强大RMI特性的提示。但我会说在你的特殊情况下尝试将服务器类传播给客户端可能不是一个好主意。想象一下,还有另一个客户端,比如并行的JMX浏览器,可能会遇到未知类的问题。更好:在发送RMI调用的结果之前在服务器端捕获itext-Exception,并通过仅使用错误消息而不是堆栈跟踪将其包装在另一个众所周知的异常中,例如IllegalStateException
(你应该在服务器端记录它。)
我在服务器端进行异常处理的想法是(伪代码):
try {
// your server code
} catch (Throwable ex) {
// a) log error completely including cause (stacktrace) with tools like Log4J etc.
// b) throw new RemoteException(error.getMessage()); // without cause!
}
答案 2 :(得分:0)
好的,我找到了解决方案。
看起来我认为是正确的 - 客户端不必了解服务器实现的内容。
所有东西的关键是我们的一个类中的静态初始化块 - 那里使用的资源无法解决。由于它是在静态块中,IOException
不是正确的,Error
生成了异常保证。将所有catch
es从Excetpion
更改为Throwable
服务器后,确实记录了具有根本原因的正确堆栈跟踪(这不包含在客户端记录的堆栈跟踪中)。修复它只是一个问题。
谢谢你的时间!