1

语境

这是一个使用 Java RMI 的应用程序,具有:

  • 主机 A 上的客户端和主机 B 上的服务器。
  • 主机 A 上的 HTTP 服务器,它保存客户端和服务器使用的所有类的副本。
  • RMI 注册表是从服务器代码创建的,它共享服务器 JVM 和 CLASSPATH。

对于服务器和客户端应用程序:

  • java.rmi.server.codebase属性(在代码中)设置为 HTTP 服务器 URL。
  • 具有适当策略的安全经理已就位。
  • java.rmi.server.hostname设置为 LAN 地址。

方法调用:

  • 服务器方法是使用类型参数WorkRequest(抽象类)定义的。
  • 客户端使用子类调用此方法WorkRequestSquare
  • WorkRequestSquare从未在服务器代码中提及

服务器代码

Object execute(WorkRequest work) throws RemoteException { return work.execute(); }

客户端代码:

try { servant.execute(new WorkRequestSquare(123)); }
catch (RemoteException e) {
    System.out.println("Error while submitting work request:");
    e.printStackTrace();
}

当服务器在 CLASSPATH 中包含所有相关类并且不需要动态加载时,此代码有效。

问题

从服务器端的 CLASSPATH 中删除WorkRequestSquare会在客户端抛出异常(服务器端不会抛出任何东西):

Error while submitting work request:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
    java.lang.ClassNotFoundException: WorkRequestSquare
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    ...

WorkRequestSquare从未在服务器代码中明确提及,它应该是可动态加载的,但这不会发生。

旁路

Stuart Marks 让我知道该属性java.rmi.server.useCodebaseOnly应设置为false.

在 JDK 7u21 中,此属性的默认值已从 更改false为。设置为防止 JVM 从任何位置动态加载类,除了使用. 这意味着客户端 JVM 在编组参数时设置的代码库值被.true useCodebaseOnlytruejava.rmi.server.codebaseWorkRequestSquareuseCodebaseOnlytrue

当在服务器上useCodebaseOnly设置为false,并且WorkRequestSquare从服务器 CLASSPATH 中删除类时,服务器现在从 HTTP 服务器获取类定义。这是一个有效的绕过。

问题

由于客户端和服务器具有相同的codebase属性值,因此仍然存在异常。

何时useCodebaseOnly默认为true服务器 JVM 应该忽略codebase添加到 RMI 流中的客户端,但无论如何它应该使用自己的codebase来检索WorkRequestSquare类。

无论如何,这应该是成功的,因为客户端和服务器codebase值是相同的。

有人可以对这件事有所了解吗?

4

1 回答 1

0

需要在类路径中的最小类集是什么?

在客户端代码中按名称实际使用的类。例如,远程接口、形式参数的类型和结果、远程方法签名中命名的异常类型。

/ 类路径中可能缺少哪些类,前提是它们可以使用代码库服务器获得?

实现上述类或接口并且在客户端代码中未按名称使用的类。

是否有调试 RMI 通信的工具(例如 Eclipse 插件)并避免使用网络嗅探器?

当然有一个 Eclipse 插件,我很多年前就看到了,但我从来没有真正需要过。

于 2014-08-14T23:11:23.517 回答