【问题标题】:Java RMI call with remote parameters fails带有远程参数的 Java RMI 调用失败
【发布时间】:2011-09-19 14:14:25
【问题描述】:

我从 RMI 注册表获得远程引用;让我们称之为s。现在,s 是(接口)类型S,它提供了一个方法m(A, B, int)

在客户端,我有AB 的实现,它们都扩展了UnicastRemoteObject(因此会自动导出)。分别考虑实例ab

现在我打电话给m(a, b, 0)。它可以编译,但在运行时失败,信息量非常少

java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)
at sun.rmi.transport.Transport$1.run(Transport.java:159)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
at $Proxy0.m(Unknown Source)
[... application specific sites]

遗憾的是,NativeMethodAccessorImpl.invoke0 是本机实现的,无法检查。所以,我完全不知所措。很明显,类型匹配,否则原代码应该编译不出来吧?

这可能是什么原因?

编辑:我们使用 Java 6。该错误可以在 Ubuntu 11.04 32bit、Ubuntu 10.10 64bit 和 Windows 7 32bit 上重现。

编辑 2: 我在 S 上实现了一些虚拟方法来测试各个参数。事实证明,s.n()s.t0(b)s.t1(0) 按预期工作;只有s.t2(a) 失败。这意味着我实现A 的方式有问题,不是吗?

AB 之间唯一显着的区别(当然,除了实际内容)是A 是一个扩展UnicastRemoteObject 的类,并且遵循远程接口的约定,但没有实现可区分的远程接口。 B 是一个远程接口,我通过了它的实现。

【问题讨论】:

  • 我猜你在没有重新运行 rmic 的情况下改变了你的接口或实现类。
  • 我们使用 Java 6,所以应该有 rmic 的需求。它自 1.5 以来一直是遗留的。
  • 你在服务器端使用了哪些 A 和 B 的实现?
  • A 的那个在服务器和客户端上都是一样的。 B 的那个只在客户端可用,服务器只知道接口B
  • 客户端和服务器是否有可能对接口'S'有不同的类文件?

标签: java rmi


【解决方案1】:

事实证明,我在第二次编辑中提供的信息至关重要。

您只能将明确实现扩展Remote 的接口的类的远程对象导出/使用。特别是,不够有一个扩展 UnicastRemoteObject 的类——即使那个类实现了 Remote!在这种情况下,一切都可以正常编译和导出,但实际上远程传递对象会导致上述异常。

我想为不存在远程接口的远程类型创建骨架/存根会以某种方式失败。应该有更好的治疗方法,但是很好。

编辑:澄清一下:UnicastRemoteObject 实现了Remote。现在,有类似的东西

class A extends UnicastRemoteObject { void m() throws RemoteException {} }

不够足够,即使A 间接实现了Remote。您将能够实例化(即导出),但不能将其作为A 远程传递。

你需要做的

interface B extends Remote { void n() throws RemoteException; }
class BImpl extends UnicastRemoteObject implements B { void n() throws RemoteException { ... } }

BImpl 的实例可以像您期望的那样以B 的形式远程传递。因此,如果您想拥有正确的远程对象,您似乎需要实现除 Remote 之外的可区分远程接口。

【讨论】:

  • 那么 A 和 B 不扩展 Remote?
  • 当然可以,但仅此还不够。我会尽力澄清。
  • 仅此一项其实就足够了。 A 和 B 都必须扩展 Remote。否则你的标题不满意,你没有远程参数。
  • 对不起;我的“当然”是指“是的,它们确实扩展了Remote”。编辑是否澄清了事情?
猜你喜欢
  • 1970-01-01
  • 2016-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多