標籤:java rmi 遠程方法調用 調用遠程對象 分散式運算
RMI(Remote Method Invocation)中文名稱是遠程方法調用,可用於分散式運算。
這裡就不去詳細介紹RMI了,本Blog主要講敘RMI實戰和有哪些需要注意的地方,如果想要查看詳細介紹請查看:百度百科RMI
RMI分為服務端和用戶端
服務端:建立服務端:
LocateRegistry.createRegistry(連接埠);Naming.rebind("rmi://IP地址:連接埠/RMI服務名稱",RMI服務物件);//rebind也可以用bind替代
樣本:
LocateRegistry.createRegistry(10010);Naming.rebind("rmi://127.0.0.1:10010/Test", new TestServer());
RMI服務物件的類定義規則:1.必須繼承UnicastRemoteObject2.構造方法必須聲明拋出RemoteException3.必須實現自訂的業務介面,不能直接實現Remote,必須將用戶端要調用的介面抽取到介面中去4.用戶端要調用的介面方法傳回值必須實現Serializable,雖然發布RMI服務時不會報錯但RMI用戶端調用此方法時會報錯RMI服務物件的介面定義規則:1.介面必須繼承Remote2.介面方法必須聲明拋出RemoteException樣本:
public interface TestServerInterface extends Remote { String getString() throws RemoteException; Student getStudent(String name) throws RemoteException;}public class TestServer extends UnicastRemoteObject implements TestServerInterface { public TestServer() throws RemoteException { super(); } @Override public String getString() throws RemoteException { return System.currentTimeMillis()+":有用戶端調用了此方法"; } @Override public Student getStudent(String name) throws RemoteException { return new Student(name+System.currentTimeMillis()); }}
用戶端:建立並使用用戶端:
RMI服務物件的介面 server= (RMI服務物件的介面) Naming.lookup("rmi://IP地址:連接埠/RMI服務名稱");傳回值 result=server.你要調用的方法(可能需要傳入的參數);
樣本:
TestServerInterface serverInterface= (TestServerInterface) Naming.lookup("rmi://localhost:10010/Test");System.out.println(">>>" + serverInterface.getString());System.out.println(">>>" + serverInterface.getStudent("name1"));
RMI服務物件的介面定義規則:
1.可以和服務端定義的介面方法不一致,服務端有的這邊可以沒有,服務端沒有的這邊可以有,但調用時會報錯
2.無須繼承Remote,繼承也行不過沒意義
3.介面方法無須聲明拋出RemoteException,聲明拋出也行不過沒意義
4.一般來說和服務端保持一致即可
樣本:
public interface TestServerInterface { String getString(); Student getStudent();}
特別說明:一、用戶端使用的”RMI服務物件的介面”和服務端用”RMI服務物件的介面”是兩個不用的類,因為用戶端和服務端一般不在一台機器上。二、如果用戶端返回的值是自訂類型,用戶端所定義接收的傳回值則有下規則:1.必須實現Serializable2.如果服務端沒有定義serialVersionUID,用戶端這邊也必須沒有定義serialVersionUID3.如果服務端有定義serialVersionUID,用戶端這邊也必須定義serialVersionUID並且serialVersionUID值要和服務端serialVersionUID值一致,否則會報未序列化和版本號碼不一致異常樣本1:服務端返回自訂類型:
public class Student implements Serializable { private static final long serialVersionUID = 1L; private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public String toString(){ return name; }}
用戶端接受自訂類型:
public class Student implements Serializable { private static final long serialVersionUID = 1L; private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public String toString(){ return name; }}
樣本2:服務端返回自訂類型:
public class Student implements Serializable { private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public String toString(){ return name; }}
用戶端接受自訂類型:
public class Student implements Serializable { private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public String toString(){ return name; }}
完整代碼:
項目圖:
服務端:
package test;import java.io.Serializable;import java.rmi.Naming;import java.rmi.Remote;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import java.rmi.server.UnicastRemoteObject;public class RmiServerMain { public static void main(String[] args) throws Exception { LocateRegistry.createRegistry(10010); Naming.bind("rmi://127.0.0.1:10010/Test", new TestServer()); }}interface TestServerInterface extends Remote { String getString() throws RemoteException; Student getStudent(String name) throws RemoteException;}class TestServer extends UnicastRemoteObject implements TestServerInterface { private static final long serialVersionUID = 1L; public TestServer() throws RemoteException { super(); } @Override public String getString() throws RemoteException { return System.currentTimeMillis() + ":有用戶端調用了此方法"; } @Override public Student getStudent(String name) throws RemoteException { return new Student(name + System.currentTimeMillis()); }}class Student implements Serializable { private static final long serialVersionUID = 110L; private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public String toString() { return getClass().getSimpleName() + ":name=" + name; }}
用戶端
package test;import java.io.Serializable;import java.rmi.Naming;public class RmiClientMain { public static void main(String[] args) throws Exception { TestServerInterface serverInterface = (TestServerInterface) Naming.lookup("rmi://127.0.0.1:10010/Test"); System.out.println(">>>" + serverInterface.getString()); System.out.println(">>>" + serverInterface.getStudent("StuName")); }}/** * 用戶端的服務介面,不是必須繼承Remote,並且方法不是必須申明拋出RemoteException<br> * 但包名、類名必須要和服務端完全一致。<br> * 方法可以刪掉、可以亂加,但亂加的方法你只要不調用就行,以調用就報錯。<br> * 方法的結構不同改,如傳回型別,參數類型。 * * @author Tang * */interface TestServerInterface { String getString(); Student getStudent(String name);}class Student implements Serializable { /** * serialVersionUID變數必須和服務端保持一致。<br> * 如果服務端沒有定義此變數,用戶端這裡也必須不要定義此變數<br> * 如果服務端有定義此變數,用戶端這裡也必須要定義此變數,並且變數的值也要相同 */ private static final long serialVersionUID = 110L; private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public String toString() { return getClass().getSimpleName() + ":name=" + name; }}
Java之RMI(遠程方法調用)