我正在尝试使用 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 应用程序开始,您可能需要按照以下步骤操作:
- >
创建接口(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; }
- >
实现接口(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; } }
- >
实现要在客户端和服务器之间传递的非原始可序列化对象:
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; } }
- >
实现服务器:
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); } } }
- >
实现客户端:
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(); } } }
一个较大的客户端-服务器应用程序应分为三个模块:client
、server
和common
(用于服务器之间共享的类)和客户端代码,即本例中的远程接口(interface)和非原始对象)。然后,客户端应用程序将从类路径上的 client
+ common
模块和 server
+ common
模块创建类路径上的模块。
我多年前使用这个示例来学习 RMI 的基础知识,它仍然有效。然而,它远非完美(使用默认 Java 包、不正确的异常处理、主机名和端口参数是硬编码的且不可配置等)
不过,这对初学者来说还是不错的。所有文件都可以放在一个目录中,并使用简单的 javac *.java
命令进行编译。然后可以使用 java SomeServer
启动服务器应用程序,并通过启动 java SomeClient
命令启动客户端应用程序。
我希望这有助于理解 Java RMI,事实上,它远比这复杂。
关于java - 我是否需要客户端、服务器和注册表上的所有类才能使 RMI 工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7083908/