Java 遠端方法調用,即 Java RMI( Java Remote Method Invocation ) 。顧名思義,可以使客戶機上運作的程式能夠調用遠端伺服器上的對象(方法)。
下面主要介紹一下使用步驟:
1.定義遠端接口(服務端)
遠端接口定義出可以讓客戶遠端調用的方法。
此接口必須實作
java.rmi.Remote
接口,來表示其支援遠端調用;同時其中聲明的所有方法,需要抛出
RemoteException
異常,因為遠端調用的不穩定性(如網絡原因等),這樣可以讓用戶端在調用失敗時進行相應的處理。
public interface DemoService extends Remote {
String sayHello() throws RemoteException;
}
2.實作遠端接口(服務端)
遠端接口的實作類如果想要被遠端通路,可以有如下實作方式:
繼承
java.rmi.server.UnicastRemoteObject
類

public class DemoServerImpl extends UnicastRemoteObject implements DemoService{
public DemoServerImpl() throws RemoteException {
// 因為 UnicastRemoteObject 構造器抛出 RemoteException
// 是以此處隻能聲明一個構造器并抛出對應異常
}
@Override
public String sayHello() throws RemoteException {
return "Hello World";
}
}

如果不想繼承
UnicastRemoteObject
類,則需要使用
UnicastRemoteObject
類的靜态方法
exportObject(Remote obj, int port)
将對象導出
其中如果端口設為 0 的話,則表示任何合适的端口都可用來監聽客戶連接配接

public class DemoServerImpl implements DemoService{
public DemoServerImpl() throws RemoteException {
UnicastRemoteObject.exportObject(this, 0);
}
@Override
public String sayHello() throws RemoteException {
return "Hello World";
}
}

這兩者方法本質上是一樣的,在
UnicaseRemoteObject
類的構造方法中,其實也是調用了
exportObject
方法

// UnicaseRemoteObject中的部分源碼
protected UnicastRemoteObject() throws RemoteException
{
this(0);
}
// if port is zero, an anonymous port is chosen
protected UnicastRemoteObject(int port) throws RemoteException
{
this.port = port;
exportObject((Remote) this, port);
}

3.啟動 RMI 系統資料庫
系統資料庫就像一個電話簿,啟動後即可将提供的服務注冊到其中,客戶可以通過它查詢到服務來進行調用
啟動系統資料庫有兩種方法,一種是通過指令行
rmiregistry
來啟動,另一種方式是通過
LocateRegistry.createRegistry(int port)
方法。
4.注冊開啟遠端服務
注冊服務共有三種方式:
- LocateRegistry 類的對象的 rebind() 和 lookup() 來實作綁定注冊和查找遠端對象的
- 利用命名服務 java.rmi.Naming 類的 rebind() 和 lookup() 來實作綁定注冊和查找遠端對象的
- 利用JNDI(Java Naming and Directory Interface,Java命名和目錄接口) java.naming.InitialContext 類來 rebind() 和 lookup() 來實作綁定注冊和查找遠端對象的
其中第二種方式實際是對第一種方式的簡單封裝,在内部仍是調用
Registry
類的
bind
方法

// Naming 類的部分源碼 (為了節省篇幅,去除了抛出異常部分)
public static void bind(String name, Remote obj) throws ...
{
ParsedNamingURL parsed = parseURL(name);
Registry registry = getRegistry(parsed);
if (obj == null)
throw new NullPointerException("cannot bind to null");
registry.bind(parsed.name, obj);
}

服務測試類:

public class ServerTest {
public static void main(String[] args) throws Exception{
String name = "rmi.service.DemoService";
// 建立服務
DemoService service = new DemoServerImpl();
// 建立本機 1099 端口上的 RMI 系統資料庫
Registry registry1 = LocateRegistry.createRegistry(1099);
/***************** 以下為注冊方法一 ************/
// 将服務綁定到系統資料庫中
registry1.bind(name, service);
/***************** 以下為注冊方法二 ************/
// Naming.bind(name, service);
/***************** 以下為注冊方法三 ************/
//Context namingContext = new InitialContext();
//namingContext.bind("rmi:" + name, service); // 此方式 name 需要以 rmi: 開頭
}
}

用戶端測試類:

public class ClientTest {
public static void main(String[] args) throws Exception {
String name = "rmi.service.DemoService";
/***************** 以下為查找服務方法一 ************/
// 擷取系統資料庫
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
// 查找對應的服務
DemoService service = (DemoService) registry.lookup(name);
/***************** 以下為查找服務方法二 ************/
// DemoService service = (DemoService) Naming.lookup(name);
/***************** 以下為查找服務方法三 ************/
//Context namingContext = new InitialContext();
//DemoService service = (DemoService) namingContext.lookup("rmi:" + name);
// 調用服務
System.out.println(service.sayHello());
}
}
轉載:https://www.cnblogs.com/zawier/p/7043855.html