java - 我是否需要客户端、服务器和注册表上的所有类才能使 RMI 工作?

标签 java classpath rmi

我正在尝试使用 RMI,我有一个简单的问题。

我有一个 .jar 文件,它实现了库中的几种方法。 我想使用 RMI 在 .jar 文件中调用此方法。

我正在尝试的是创建一种包装器来完成它。

所以,我正在做这样的事情:

接口(interface)类:该接口(interface)具有远程对象要实现的方法。

实现类:该类,具有接口(interface)方法的实现,每个实现调用.jar文件中对应的方法。例如,jar 文件有一个名为 getDetails() 的方法,它返回一个“ResponseDetail”对象。 ResponseDetail 是我在 .jar 中的响应类。

服务器类:它将方法绑定(bind)到 rmiregistry

客户端类:它将使用实现中实现的方法。

到目前为止还好吗? :)

现在,我有一个 lib 文件夹,其中包含 .jar 文件。

服务器 机器上,我部署了接口(interface)、实现和服务器类。我已经生成了 stub ,并且成功运行了 rmiregistry,但是,这些细节:

要启动 rmiregistry,我必须在命令行中设置类路径以引用 .jar 文件,否则我会得到 java.lang.NoClassDefFoundError。我是用这个 .sh 文件做的:

THE_CLASSPATH=
for i in `ls ./lib/*.jar`
do
    THE_CLASSPATH=${THE_CLASSPATH}:${i}
done

rmiregistry -J-classpath -J".:${THE_CLASSPATH}" 

要启动服务器,我还必须设置类路径以引用 .jar 文件,否则,我会得到 java.lang.NoClassDefFoundError。我用过这样的东西:

THE_CLASSPATH=
for i in `ls ./lib/*.jar` do
  THE_CLASSPATH=${THE_CLASSPATH}:${i}
done

java -classpath ".:${THE_CLASSPATH}" Server

客户端机器: 要从客户机运行 Client.class 文件,我必须将 .jar 文件复制到它,并在类路径中引用它们,否则它不会运行,并且我得到 java.lang.NoClassDefFoundError。我不得不在客户端机器上使用它:

THE_CLASSPATH=
for i in `ls ./lib/*.jar`
do
   THE_CLASSPATH=${THE_CLASSPATH}:${i}
done

java -classpath ".:${THE_CLASSPATH}" HelloClient

这样可以吗?我的意思是,我是否必须将 .jar 文件复制到客户端计算机才能通过 RMI 执行方法?

最佳答案

在 JDK v5 之前,必须使用 rmic(RMI 编译器)生成 RMI stubc。这是从 JDK v5 开始自动完成的。此外,您还可以从 Java 代码中启动 RMI 注册表。要从一个简单的 RMI 应用程序开始,您可能需要按照以下步骤操作:

  1. > 创建接口(interface):
    
    import java.rmi.*;
    public interface SomeInterface extends Remote {
      public String someMethod1() throws RemoteException;
      public int someMethod2(float someParameter) throws RemoteException;
      public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException;
    }
    
  2. > 实现接口(interface):
    
    import java.rmi.*;
    import java.rmi.server.*;
    public class SomeImpl extends UnicastRemoteObject implements SomeInterface {
      public SomeImpl() throws RemoteException {
        super();
      }
      public String someMethod1() throws RemoteException {
        return "Hello World!";
      }
      public int someMethod2( float f ) throws RemoteException {
        return (int)f + 1;
      }
      public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException {
        int i = someStruct.getInt();
        float f = someStruct.getFloat();
        someStruct.setInt(i + 1);
        someStruct.setFloat(f + 1.0F);
        return someStruct;
      }
    }
    
  3. > 实现要在客户端和服务器之间传递的非原始可序列化对象:
    
    import java.io.*;
    public class SomeStruct implements Serializable {
      private int i = 0;
      private float f = 0.0F;
      public SomeStruct(int i, float f) {
        this.i = i;
        this.f = f;
      }
      public int getInt() {
        return i;
      }
      public float getFloat() {
        return f;
      }
      public void setInt(int i) {
        this.i = i;
      }
      public void setFloat(float f) {
        this.f = f;
      }
    }
    
  4. > 实现服务器:
    
    import java.rmi.*;
    import java.rmi.server.*;
    import java.rmi.registry.Registry;
    import java.rmi.registry.LocateRegistry;
    import java.net.*;
    import java.io.*;
    public class SomeServer  {
      public static void main(String args[]) {
        String portNum = "1234", registryURL;
        try{   
          SomeImpl exportedObj = new SomeImpl();
          startRegistry( Integer.parseInt(portNum) );
          // register the object under the name "some"
          registryURL = "rmi://localhost:" + portNum + "/some";
          Naming.rebind(registryURL, exportedObj);
          System.out.println("Some Server ready.");
        } catch (Exception re) {
          System.out.println("Exception in SomeServer.main: " + re);
        }
      }
      // This method starts a RMI registry on the local host, if it
      // does not already exist at the specified port number.
      private static void startRegistry(int rmiPortNum) throws RemoteException{
        try {
          Registry registry = LocateRegistry.getRegistry(rmiPortNum);
          registry.list( );  
          // The above call will throw an exception
          // if the registry does not already exist
        } catch (RemoteException ex) {
          // No valid registry at that port.
          System.out.println("RMI registry is not located at port " + rmiPortNum);
          Registry registry = LocateRegistry.createRegistry(rmiPortNum);
          System.out.println("RMI registry created at port " + rmiPortNum);
        }
      }
    }
    
  5. > 实现客户端:
    
    import java.io.*;
    import java.rmi.*;
    import java.rmi.registry.Registry;
    import java.rmi.registry.LocateRegistry;
    public class SomeClient {
      public static void main(String args[]) {
        try {
          String hostName;
          String portNum = "1234";
          String registryURL = "rmi://localhost:" + portNum + "/some";
          SomeInterface h = (SomeInterface)Naming.lookup(registryURL);
          // invoke the remote method(s)
          String message = h.someMethod1();
          System.out.println(message);
          int i = h.someMethod2(12344);
          System.out.println(i);
          SomeStruct someStructOut = new SomeStruct(10, 100.0F);
          SomeStruct someStructIn  = new SomeStruct(0, 0.0F);
          someStructIn = h.someStructTest(someStructOut);
          System.out.println( someStructIn.getInt() );
          System.out.println( someStructIn.getFloat() );
        } catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    }
    

一个较大的客户端-服务器应用程序应分为三个模块:clientservercommon(用于服务器之间共享的类)和客户端代码,即本例中的远程接口(interface)和非原始对象)。然后,客户端应用程序将从类路径上的 client + common 模块和 server + common 模块创建类路径上的模块。

我多年前使用这个示例来学习 RMI 的基础知识,它仍然有效。然而,它远非完美(使用默认 Java 包、不正确的异常处理、主机名和端口参数是硬编码的且不可配置等)

不过,这对初学者来说还是不错的。所有文件都可以放在一个目录中,并使用简单的 javac *.java 命令进行编译。然后可以使用 java SomeServer 启动服务器应用程序,并通过启动 java SomeClient 命令启动客户端应用程序。

我希望这有助于理解 Java RMI,事实上,它远比这复杂。

关于java - 我是否需要客户端、服务器和注册表上的所有类才能使 RMI 工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7083908/

相关文章:

jsp - 尝试添加新类错误: import cannot be resolved

Java list 文件类路径及其如何确定相对死亡

java - 使用 java RMI 和 CORBA 的分布式计算

Java RMI 代理转换问题

java - 我必须如何配置 RMI 环境才能在 "real"网络中使用它?

c# - C# 中 override 和 virtual 的使用 vs. Java 方法覆盖

java - Spring AOP 可重入方面

java - Maven Surefire 测试中的 ClassNotFoundExceptions

java - 为什么数据库查询的结果通常类型不安全?

java - 构建要在 Highchart 中显示的动态数量的数组