我是否需要客户端,服务器和注册表上的所有类才能使用RMI?

Fer*_*ano 7 java rmi classpath

我正在用RMI做我的第一步,我有一个简单的问题.

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

我正在尝试创建一种包装来做它.

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

接口类:此接口具有远程对象要实现的方法.

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

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

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

到现在为止还挺好?:)

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

服务器机器中,我已经部署了Interface,Implementation和Server类.我已经生成了存根,并成功运行了rmiregistry,但是,有了这些细节:

要启动rmiregistry,我必须在命令行中设置classpath来引用.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}" 
Run Code Online (Sandbox Code Playgroud)

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

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

java -classpath ".:${THE_CLASSPATH}" Server
Run Code Online (Sandbox Code Playgroud)

客户端机器: 要从客户端机器运行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
Run Code Online (Sandbox Code Playgroud)

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

Jir*_*era 7

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

  1. 创建界面:
    
    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;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 实现界面:
    
    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;
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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;
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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);
        }
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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();
        }
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

较大的客户端 - 服务器应用程序应分为三个模块:client,servercommon(对于服务器和客户端代码之间共享的类,即本示例中的远程接口和非基本对象).客户端应用程序将被从创建client+ common类路径上的,并从服务器模块server+ common类路径上的模块.

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

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

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


jta*_*orn 3

您不应该生成存根(如果您正在遵循教程,那么它已经旧了)。您可以运行客户端,而不必在本地拥有 jar(使用远程类加载),但是使用本地可用的 jar 来实现这一点要容易得多(我个人已经完成了相当多的 RMI,并且从未实际部署过具有远程类加载的系统) )。通常,您需要 2 个 jar,一个仅包含远程接口(以及这些接口使用的任何可序列化类)的“客户端”jar 和一个包含实现类的“服务器”jar。然后,您将使用服务器 jar 运行服务器,并使用客户端 jar 运行 rmiregistry/client。

这是一个非常好的(最新且简单)的入门指南