本博客 貓叔的博客,轉載請申明出處
學習系列
Java自帶RPC實現,RMI框架入門
首先RMI(Remote Method Invocation)是Java特有的一種RPC實現,它能夠使部署在不同主機上的Java對象進行通信與方法調用,它是一種基於Java的遠程方法調用技術。
讓我們優先來實現一個RMI的RPC案例吧。
項目源碼地址:RPC_Demo,記得是項目裏面的comgithubrmi
- 1、首先我們需要爲服務端創建一個接口方法,而且這個接口最好繼承
Remote
package com.github.rmi.server;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* Create by UncleCatMySelf in 21:03 2019\4\20 0020
*/
public interface MyService extends Remote {
String say(String someOne)throws RemoteException;
}
- 2、對於接口實現類,RMI接口方法定義必須顯式聲明拋出RemoteException異常,服務端方法實現必須繼承UnicastRemoteObject類,該類定義了服務調用與服務提供方對象實現,並建立一對一的連接。
package com.github.rmi.server;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* Create by UncleCatMySelf in 21:05 2019\4\20 0020
*/
public class MyServiceImpl extends UnicastRemoteObject implements MyService {
protected MyServiceImpl() throws RemoteException {
}
public String say(String someOne) throws RemoteException {
return someOne + ",Welcome to Study!";
}
}
- 3、這裏我們還需要一個針對服務端的配置類,因爲RMI的通信端口是隨機產生的,因此有可能會被防火牆攔截。爲了防止被防火牆攔截,需要強制制定RMI的通信端口,一般通過自定義一個RMISocketFactory類來實現。
package com.github.rmi.config;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.server.RMISocketFactory;
/**
* Create by UncleCatMySelf in 21:15 2019\4\20 0020
*/
public class CustomerSocketFactory extends RMISocketFactory {
public Socket createSocket(String host, int port) throws IOException {
return new Socket(host, port);
}
public ServerSocket createServerSocket(int port) throws IOException {
if (port == 0){
port = 8855;
}
System.out.println("RMI 通信端口 : " + port);
return new ServerSocket(port);
}
}
- 4、好了,這時你可以寫出服務端的啓動代碼了。
package com.github.rmi.server;
import com.github.rmi.config.CustomerSocketFactory;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.RMISocketFactory;
/**
* Create by UncleCatMySelf in 21:07 2019\4\20 0020
*/
public class ServerMain {
public static void main(String[] args) throws Exception {
//註冊服務
LocateRegistry.createRegistry(8866);
//指定通信端口,防止被防火牆攔截
RMISocketFactory.setSocketFactory(new CustomerSocketFactory());
//創建服務
MyService myService = new MyServiceImpl();
Naming.bind("rmi://localhost:8866/myService",myService);
System.out.println("RMI 服務端啓動正常");
}
}
- 5、客戶端的啓動就相對比較簡單,我們僅需要進入服務,並調用對應的遠程方法即可。
package com.github.rmi.client;
import com.github.rmi.server.MyService;
import java.rmi.Naming;
/**
* Create by UncleCatMySelf in 21:10 2019\4\20 0020
*/
public class ClientMain {
public static void main(String[] args) throws Exception {
//服務引入
MyService myService = (MyService) Naming.lookup("rmi://localhost:8866/myService");
//調用遠程方法
System.out.println("RMI 服務端調用返回:" + myService.say("MySelf"));
}
}
最後可以看看效果。
關於RMI的一些關鍵點
- 支持真正的面向對象的多態性,這是RMI的優勢。
- 完美支持Java語言所獨有的特性,不支持其他語言。
- 使用了Java原生序列化,所有序列化對象必須實現java.io.Serializablie接口。
- 底層通信是BIO(同步阻塞I/O)實現的Socket
- 由於BIO與原生序列化存在的性能問題,導致RMI的性能較差,如果你的項目性能要求較高,可能並不合適哦!
公衆號:Java貓說
學習交流羣:728698035
現架構設計(碼農)兼創業技術顧問,不羈平庸,熱愛開源,雜談程序人生與不定期乾貨。