Java rmi踩坑总结

最近在做分布式计算作业的过程中,需要用到Java rmi实现RPC远程调用,踩了不少坑,来总结一下帮助大家避坑。

服务端报错:

java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:…………
Caused by: java.lang.ClassNotFoundException: com.basics.RMI…………

原因是rmiregistry注册中心没有找到接口,这个跟rmiregistry启动的位置有关。必须在编译文件(class文件)的最上层目录下启动rmiregistry才能让注册中心找到正确的类。

解决方法:例如我编译好的class文件都放在output目录下,如图所示:

打开一个终端,一定要cd到output目录下,再启动rmiregistry,就OK了

再次运行服务端,发现没有报错,一切正常。

客户端报错:

Exception:java.lang.ClassCastException: class jdk.proxy1.$Proxy0 cannot be cast to class com.stu.Client.RPCinterface (jdk.proxy1.$Proxy0 is in module jdk.proxy1 of loader 'app'; com.stu.Client.RPCinterface is in unnamed module of loader 'app')
java.lang.ClassCastException: class jdk.proxy1.$Proxy0 cannot be cast to class com.stu.Client.RPCinterface (jdk.proxy1.$Proxy0 is in module jdk.proxy1 of loader 'app'; com.stu.Client.RPCinterface is in unnamed module of loader 'app')
    at com.stu.Client.RMIClient.main(RMIClient.java:20)

原因是Java rmi要求服务端与客户端的接口的类的全限定名必须保持完全一致(全限定名=包名 + 类型名)。例如下图的错误示例中,我之前错把客户端Clinet与服务端Server的RPCinterface分别放到了两个包中(com.stu.Client和com.stu.Server),这就导致了RPCinterface接口的全限定名不一致,进而导致类型转换错误。

解决方法,把RPCinterface放在一个单独的包里,不再区分Client和Server,如下图所示:新建一个com.stu.Com包,单独放RPCinterface。(注意,该方法只适合用于客户端与服务端都是同一个本地机运行的情况,用于调试程序。更加通用的做法是把RPCinterface打成一个jar包来用)

序列化问题

Exception:java.rmi.MarshalException: error marshalling arguments; nested exception is: 
    java.io.NotSerializableException: com.stu.Entity.Student
java.rmi.MarshalException: error marshalling arguments; nested exception is: 
    java.io.NotSerializableException: com.stu.Entity.Student
    at java.rmi/sun.rmi.server.UnicastRef.invoke(UnicastRef.java:161)
    at java.rmi/java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:215)
    at java.rmi/java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:160)
    at jdk.proxy1/jdk.proxy1.$Proxy0.add(Unknown Source)
    at com.stu.Client.RMIClient.main(RMIClient.java:45)
Caused by: java.io.NotSerializableException: com.stu.Entity.Student
    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1197)
    at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
    at java.rmi/sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:294)
    at java.rmi/sun.rmi.server.UnicastRef.invoke(UnicastRef.java:156)
    ... 4 more
​
Process finished with exit code 0
 

如果自定义了类,需要考虑序列化的问题。请在自定义类中实现Serializable接口,添加UID字段。

例如:

public class User implements Serializable {
    // 该字段必须存在
    private static final long serialVersionUID = 42L;
    // setter和getter可以没有
    String name;
    int id;
​
    public User(String name, int id) {
        this.name = name;
        this.id = id;
    }
}

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java RMI(远程方法调用)是Java语言中的一项技术,可以让分散在不同计算机上的程序之间进行远程通信。Java RMI使用Java的序列化机制来传递消息和参数,并通过Java虚拟机(JVM)来实现对远程对象的调用。对于数据库应用而言,Java RMI可以通过网络将客户端与服务器连接起来,并提供一种基于Java的分布式数据库交互方式。 使用Java RMI来连接数据库,可以使得客户端和服务器端的计算机分别处于不同的地点,甚至可以位于不同的城市、不同的国家或不同的大洲。这种分布式的架构使得客户端在终端上只需要安装少量的软件,并且大部分工作都由服务器端完成。同时,Java RMI提供了良好的安全性和稳定性,可以保证数据的安全性和完整性。 对于Java RMI连接数据库的实现,需要涉及到几个方面的知识点。首先是Java的JDBC技术,通过JDBC可以实现对于数据库的访问操作。其次是Java RMI的远程调用机制,需要实现远程对象(Remote Object)的创建。在客户端和服务器端之间建立连接后,客户端可以通过远程对象来调用服务器端提供的操作,并将数据从客户端传递到服务器端进行处理。 总的来说,Java RMI 数据库架构的实现可以为企业提供便捷的分布式数据库操作服务,提高数据安全性和稳定性,并且可以支持异构系统之间的数据共享和集成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值