![](/img/trans.png)
[英]How do I register a server in the default RMI registry for JBoss and access it from a client running in another JVM?
[英]Do I need all classes on the client, server and registry for RMI to work?
我正在使用 RMI 邁出第一步,我有一個簡單的問題。
我有一個 .jar 文件,它實現了庫中的幾種方法。 我想使用 RMI 在 .jar 文件中調用此方法。
我正在嘗試創建一種包裝器來做到這一點。
所以,我正在做這樣的事情:
接口 class :該接口具有由遠程 object 實現的方法。
實現class :這個class,有接口方法的實現,每個實現調用.jar文件中對應的方法。 例如,jar 文件有一個名為 getDetails() 的方法,它返回一個“ResponseDetail” object。 ResponseDetail 是我在.jar 中的響應 class。
服務器 class :它將方法綁定到 rmiregistry
客戶端 class :它將使用在 implementation 中實現的方法。
到目前為止,一切都很好? :)
現在,我有一個 lib 文件夾,其中包含 .jar 文件。
在服務器機器中,我部署了接口、實現和服務器類。 我已經生成了存根,並且成功運行了 rmiregistry,但是,有以下詳細信息:
要啟動 rmiregistry,我必須在命令行中設置類路徑以引用 .jar 文件,否則我會得到 java.lang.NoClassDefFoundError。 我用 this.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 文件復制到它,並在類路徑中引用它們,否則,它不會運行,我得到 Z93F725A074B33FE1C886ZlangD48886Zlang44。 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 存根。 這是從 JDK v5 開始自動完成的。 此外,您還可以從 Java 代碼中啟動 RMI 注冊表。 要從一個簡單的 RMI 應用程序開始,您可能需要執行以下步驟:
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; }
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
(用於服務器和客戶端代碼之間共享的類,即本例中的遠程接口和非原始 object)。 然后,客戶端應用程序將從類路徑上的client
+ common
模塊創建,而服務器則從類路徑上的server
+ common
模塊創建。
多年前我用這個例子來學習 RMI 的基礎知識,它仍然有效。 然而它遠非完美(默認 Java package 使用,錯誤的異常處理,主機名和端口參數是硬編碼且不可配置等)
盡管如此,它對初學者來說還是有好處的。 所有文件都可以放在一個目錄中,並使用簡單的javac *.java
命令進行編譯。 然后可以使用java SomeServer
啟動服務器應用程序,並通過啟動java SomeClient
命令啟動客戶端應用程序。
我希望這有助於理解 Java RMI,事實上,它遠比這復雜得多。
您不應該生成存根(如果您正在學習教程,那么它已經過時了)。 您可以運行客戶端而不必在本地使用 jars(使用遠程類加載),但是使用本地可用的jars更容易做到這一點(我個人做了相當多的 RMI 並且從未實際部署具有遠程類加載的系統)。 通常,您需要 2 個 jars,一個“客戶端”jar,只有遠程接口(以及這些接口使用的任何可序列化類)和一個“服務器”jar,其中包括實現類。 然后,您將使用服務器 jar 運行服務器,並使用客戶端 jars 運行 rmiregistry/client。
這是一個很好的(最新且簡單的) 入門指南。
簡而言之,其他答案的詳細說明是:
客戶端只需要公共接口(和客戶端類),而不需要服務器實現。
服務器需要接口和實現(以及您的服務器主類)。
rmiregistry 只需要接口。
(實際上,您可以在服務器進程中啟動自己的注冊表 - 然后您根本不需要rmiregistry
。請查看java.rmi.registry.LocateRegistry
class 中的createRegistry
方法。)
這里的“接口”是指遠程接口和它們用作參數或參數類型的任何(可序列化)類。
如何將這些類分發到 jar 文件與此無關。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.