RPC框架是啥之Java自帶RPC實現,RMI框架入門

本博客 貓叔的博客,轉載請申明出處

學習系列

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"));
    }

}

最後可以看看效果。

image
image

關於RMI的一些關鍵點

  • 支持真正的面向對象的多態性,這是RMI的優勢。
  • 完美支持Java語言所獨有的特性,不支持其他語言。
  • 使用了Java原生序列化,所有序列化對象必須實現java.io.Serializablie接口。
  • 底層通信是BIO(同步阻塞I/O)實現的Socket
  • 由於BIO與原生序列化存在的性能問題,導致RMI的性能較差,如果你的項目性能要求較高,可能並不合適哦!

公衆號:Java貓說

學習交流羣:728698035

現架構設計(碼農)兼創業技術顧問,不羈平庸,熱愛開源,雜談程序人生與不定期乾貨。

Image Text

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章