草庐IT

Java RMI 和 ClassNotFoundException

coder 2023-09-03 原文

我刚开始学习如何使用 RMI,我有一个问题。我有以下目录结构:

compute.jar
client
     |
     org\examples\rmi\client
                           |--> ComputePi     // client main
                           |--> Pi            // implements Task
     org\examples\rmi\compute
                           |--> Compute       // interface
                           |--> Task          // interface

server
     |
     org\examples\rmi\engine
                           |--> ComputeEngine // server main, implements Compute
     org\examples\rmi\compute
                           |--> Compute       // interface
                           |--> Task          // interface

这是 ComputePi 类中的 main 方法:

if (System.getSecurityManager() == null) {
  System.setSecurityManager(new SecurityManager());
}
try {
  String name = "Compute";
  // args[0] = 127.0.0.1, args[1] is irrelevant
  Registry registry = LocateRegistry.getRegistry(args[0], 0);
  Compute comp = (Compute) registry.lookup(name);
  Pi task = new Pi(Integer.parseInt(args[1]));
  BigDecimal pi = comp.executeTask(task);
  System.out.println(pi);
}
catch (Exception e) {
  System.err.println("ComputePi exception:");
  e.printStackTrace();
}

这是 ComputeEngine 类中的 main 方法:

if (System.getSecurityManager() == null) {
  System.setSecurityManager(new SecurityManager());
}
try {
  String name = "Compute";
  Compute engine = new ComputeEngine();
  Compute stub = (Compute) UnicastRemoteObject.exportObject(engine, 0);
  Registry registry = LocateRegistry.getRegistry();
  registry.rebind(name, stub);
  System.out.println("ComputeEngine bound.");
}
catch (Exception e) {
  System.err.println("ComputeEngine exception: ");
  e.printStackTrace();
}

这是 executeTask 方法,也在 ComputeEngine 类中:

  public <T> T executeTask(Task<T> task) throws RemoteException {
    if (task == null) {
      throw new IllegalArgumentException("task is null");
    }
    return task.execute();
  }

RMI 注册表和服务器启动正常。以下是服务器的参数:

C:\Users\Public\RMI\server>set CLASSPATH=
C:\Users\Public\RMI\server>start rmiregistry
C:\Users\Public\RMI\server>java -Djava.rmi.server.codebase="file:/C:/Users/Public/RMI/compute.jar" -Djava.rmi.server.hostname=127.0.0.1 -Djava.security.policy=server.policy org.examples.rmi.engine.ComputeEngine

这里是客户端的参数:

C:\Users\Public\RMI\client>java -Djava.rmi.server.codebase="file:/C:/Users/Public/RMI/compute.jar" -Djava.security.policy=client.policy org.examples.rmi.client.ComputePi 127.0.0.1 45

但是,当我尝试运行客户端时出现以下异常:

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
        java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
        java.lang.ClassNotFoundException: org.examples.rmi.client.Pi
        at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
        at sun.rmi.transport.Transport$1.run(Unknown Source)
        at sun.rmi.transport.Transport$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Unknown Source)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
        at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
        at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
        at sun.rmi.server.UnicastRef.invoke(Unknown Source)
        at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
        at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
        at $Proxy0.executeTask(Unknown Source)
        at org.examples.rmi.client.ComputePi.main(ComputePi.java:38)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
        java.lang.ClassNotFoundException: org.examples.rmi.client.Pi
        at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
        at sun.rmi.transport.Transport$1.run(Unknown Source)
        at sun.rmi.transport.Transport$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Unknown Source)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.examples.rmi.client.Pi
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Unknown Source)
        at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
        at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
        at java.rmi.server.RMIClassLoader$2.loadClass(Unknown Source)
        at java.rmi.server.RMIClassLoader.loadClass(Unknown Source)
        at sun.rmi.server.MarshalInputStream.resolveClass(Unknown Source)
        at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
        at java.io.ObjectInputStream.readClassDesc(Unknown Source)
        at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
        at java.io.ObjectInputStream.readObject0(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at sun.rmi.server.UnicastRef.unmarshalValue(Unknown Source)
        ... 11 more

但是如果我将 Pi.class 文件添加到服务器目录:

server
     |
     org\examples\rmi\engine
                           |--> ComputeEngine // server main, implements Compute
     org\examples\rmi\compute
                           |--> Compute       // interface
                           |--> Task          // interface
     org\examples\rmi\client
                           |--> Pi            // same as Pi for client

程序有效。我的问题是,Pi.class 真的需要在服务器上才能让我的程序运行吗?我的理解是(如果我错了请纠正我)我将该类的一个实例发送到服务器,服务器会知道如何处理它,即它不关心实现。有人可以解释 RMI 在我的案例中是如何工作的吗?对此,我真的非常感激。谢谢!

最佳答案

我在同一网络中用两台 PC 试过这个例子。一个使用 Java 1.7.0_40 作为服务器,另一个使用 Java 1.7.0_45 作为客户端。两台 PC 都是基于 Windows 的。我遇到了 denshaotoko 提出的同样问题。

解决方法是:

服务器端:

C:\>start rmiregistry -J-Djava.rmi.server.useCodebaseOnly=false

Java 7 需要 -J-Djava.rmi.server.useCodebaseOnly 选项,因为默认值为 true,这意味着 RMI Registry 将不会查找除启动目录之外的其他代码库。那么下一步启动服务器就会失败。详情见这里:http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/enhancements-7.html

C:\>java -cp c:\rmi;c:\rmi\compute.jar -Djava.rmi.server.useCodebaseOnly=false -Djava.rmi.server.codebase=file:/c:/rmi/compute.jar -Djava.rmi.server.hostname=192.168.1.124 -Djava.security.policy=c:\rmi\server.policy engine.ComputeEngine

同样,java.rmi.server.useCodebaseOnly 应该设置为 false。否则服务器将不会使用客户端提供的代码库。然后客户端将得到类未找到异常。 192.168.1.124的主机名是服务器的IP地址

您应该获得“ComputeEngine 绑定(bind)”

客户端:

C:\>java -cp c:\rmi;c:\rmi\compute.jar -Djava.rmi.server.codebase=http://54.200.126.244/rmi/ -Djava.security.policy=c:\rmi\client.policy client.ComputePi 192.168.1.124 45 

我尝试了 file:/URL 但没有成功。我觉得原因很简单。有太多的安全限制使得服务器无法访问客户端 PC 上的文件。所以我把 Pi.class 文件放在我的网络服务器上,它位于 rmi 目录下的 http://54.200.126.244。我的网络服务器使用 Apache。任何PC都可以访问http://54.200.126.244/rmi/ 这样问题就干净解决了。

最后,您应该能够使用相同的命令从任何目录启动 rmiregistry、服务器和客户端。否则即使你能成功,有些设置可能还是不正确。例如,如果您从包含“compute”目录的目录启动 rmiregistry(在我的例子中是 C:\rmi),rmiregistry 将直接从它的起始目录加载 Compute.class 和 Task.class,因此 -Djava 的设置.rmi.server.codebase=file:/c:/rmi/compute.jar 变得无用。

关于Java RMI 和 ClassNotFoundException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11273353/

有关Java RMI 和 ClassNotFoundException的更多相关文章

  1. java - 使用 spring-web.jar 获取 java.lang.ClassNotFoundException : org. springframework.web.filter.DelegatingFilterProxy - 2

    当tomcat启动时,我在org.springframework.web.filter.DelegatingFilterProxy上得到ClassNotFoundException,我已经包含了spring-web.jar,它有类org.springframework.web.filter.DelegatingFilterProxy。来自tomcat的完整消息是-->???????,?????:??:?????????org.apache.catalina.core.AprLifecycleListenerinitINFO:TheAPRbasedApacheTomcatNativeli

  2. jdk1.5 中的 javax.xml.bind.JAXBException [java.lang.ClassNotFoundException : com. sun.xml.bind.v2.ContextFactory] - 2

    我收到错误:javax.xml.bind.JAXBException-withlinkedexception:[java.lang.ClassNotFoundException:com.sun.xml.bind.v2.ContextFactory]atjavax.xml.bind.ContextFinder.newInstance(ContextFinder.java:195)atjavax.xml.bind.ContextFinder.find(ContextFinder.java:381)atjavax.xml.bind.JAXBContext.newInstance(JAXBCo

  3. xml - ClassNotFoundException : org. apache.xml.serializer.TreeWalker - 2

    我用xml数据库和appachetomcat编写了一个简单的应用程序。我工作得很好,直到我试图在工作区打开时压缩它。之后,无论何时我尝试立即创建tomcat服务器,我都会收到此错误:ClassNotFoundException:org.apache.xml.serializer.TreeWalker所以我离开了这个。现在我正在研究xmlspy,试图使用tomcatFO引擎生成一个pdf文件。我安装了新的tomcat并在xmlspy中指出了这一点。现在,当我尝试在xmlspy中运行fo时,出现以下错误。注意:serializer.jar和xalanjar文件已经在lib文件夹中。log4

  4. Caused by: java.lang.ClassNotFoundException: com.alibaba.druid.filter.logging.Log4j2Filter - 2

    最开始遇到这个错误,百度,网上一堆的清一色解决方案,缺少log4j,引入log4j相关依赖,或者引入slf4j-over-log4j的依赖,但是好像都不行,最后还是谷歌靠谱,直接检索出github上的解决方案,这才解决了问题。查看github的解决方案:https://github.com/alibaba/druid/issues/2942如果网络比较慢,访问不了github也没有关系,看下面就好。你安装的应该是低版本的druid没有这个类,升级到新版;指定druid-spring-boot-starter但没指定druid也可能出现这个错误com.alibabadruid1.1.10com.

  5. 【IDEA】彻底解决java.lang.ClassNotFoundException: com.mysql.jdbc.Driver - 2

    最开始出现这个问题,是我在写一个MVC的JAVAWEB项目中遇到的,卡了将近两个小时。先来复述一下我当时遇到的问题吧,我在DBHelper类中测试成功了可以连接上数据库。importjava.sql.Connection;importjava.sql.DriverManager;publicclassDBHelper{privatestaticfinalStringdriver="com.mysql.jdbc.Driver";privatestaticfinalStringurl="jdbc:mysql://localhost:3306/jsp?useUnicode=true&characte

  6. php - Symfony 4 - ClassNotFoundException 内核 - 2

    我实际上是将我的symfony3.4项目升级到symfony4.0。使用composerupdate从我的gitlab存储库克隆bundle后,出现错误:ClassNotFoundExceptionAttemptedtoloadclass"Kernel"fromnamespace"App".Didyouforgeta"use"statementfor"Symfony\Component\HttpKernel\Kernel"?inindex.php(line32)好的...简单...转到index.php第32行...但是,Kernel加载了App\Kernel,所以知道为什么我会出现此

  7. php - 部署 Symfony 应用程序 - ClassNotFoundException 错误 - 2

    我正在学习Symfony框架,并尝试使用Git将我放在一起的简单样板应用程序部署到Heroku。由于以下fatalerror,部署失败:未捕获的Symfony\Component\Debug\Exception\ClassNotFoundException:尝试从命名空间“Symfony\Bundle\WebServerBundle”加载类“WebServerBundle”您是否忘记了另一个命名空间的“use”语句?在/tmp/build_cbeb92af6c9ee04b07e1f85618211649/src/Kernel.php:32内核.phpgetProjectDir().'/

  8. java - ClassNotFoundException : org. springframework.web.context.ContextLoaderListener 问题 - 2

    我在我的项目中遇到了一些问题,这是一个SpringMVC项目。在这个项目中,对于持久层,我们使用Hibernate。下面是我的web.xml详细信息:springorg.springframework.web.servlet.DispatcherServlet1spring/contextConfigLocation/WEB-INF/beanRefFactory.xmlorg.springframework.web.context.ContextLoaderListener当我尝试运行这个项目时,出现以下错误:java.lang.ClassNotFoundException:org.s

  9. java.lang.ClassNotFoundException : javax. servlet.jsp.SkipPageException 异常 - 2

    Whenirunthejsppageiamgettingthefollowingerror.Websever:Tomcat6.0,usingStrutsjava.lang.ClassNotFoundException:javax.servlet.jsp.SkipPageExceptionatorg.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1680)atorg.apache.catalina.loader.WebappClassLoader.loadClass(WebappClas

  10. java.lang.ClassNotFoundException : org. jboss.logging.Logger 错误 - 2

    我有一个奇怪的问题。我有一个JMS客户端应用程序和MDB在JBossjboss-5.1.0.GA中配置。早些时候,我通过“配置构建路径”→“添加外部JAR”添加了JAR,一切正常。现在,我将所有JAR移至项目下的lib文件夹,并使用“配置构建路径”→“添加JAR”。现在,我在执行客户端程序时遇到以下异常:(Exceptioninthread"main"java.lang.NoClassDefFoundError:org/jboss/logging/Loggeratorg.jnp.interfaces.NamingContext.(NamingContext.java:160)atorg

随机推荐