java實現簡單的RPC


在這里要用到設計模式jdk的動態代理(不會的參考)

思路解釋:

為什么要用RPC的框架?

引用(https://www.cnblogs.com/winner-0715/p/5847638.html)

目前有很多Java的RPC框架,有基於Json的,有基於XML,也有基於二進制對象的。

論復雜度,RPC框架肯定是高於簡單的HTTP接口的。但毋庸置疑,HTTP接口由於受限於HTTP協議,需要帶HTTP請求頭,導致傳輸起來效率或者說安全性不如RPC。

現在問題是,遇到怎樣的瓶頸了才需要或者說更適合用RPC(比如像阿里這么大的請求並發量,簡單的HTTP肯定達不到預期),但問題是大家所在的公司,要有像阿里這么大的量是比較少的,甚至說1/1000的量可能都沒有,那我們還需要使用RPC嗎?

技術應該不是為了使用新技術而去使用,而應該是舊技術存在某些瓶頸,存在難以支撐或者擴展性越老越差等問題暴露出來之后,用新技術來進行解決。

那RPC最大的優點,或者說它相比簡單的HTTP接口,它的優勢、更適合它的業務場景是怎樣呢?簡單的HTTP又哪里不足,哪些場景明顯不太適合呢?

---

RPC=Remote Produce Call 是一種技術的概念名詞. HTTP是一種協議,RPC可以通過HTTP來實現,也可以通過Socket自己實現一套協議來實現.所以樓主可以換一個問法,為何RPC還有除HTTP 之外的實現法,有何必要.畢竟除了HTTP實現外,私有協議不具備通用性.那么我想唯一的答案就在於HTTP不能滿足其業務場景的地方,所以這個就要具體 案例具體分析了.

------

http接口是在接口不多、系統與系統交互較少的情況下,解決信息孤島初期常使用的一種通信手段;優點就是簡單、直接、開發方便。利用現成的http協議 進行傳輸。但是如果是一個大型的網站,內部子系統較多、接口非常多的情況下,RPC框架的好處就顯示出來了,首先就是長鏈接,不必每次通信都要像http 一樣去3次握手什么的,減少了網絡開銷;其次就是RPC框架一般都有注冊中心,有豐富的監控管理;發布、下線接口、動態擴展等,對調用方來說是無感知、統 一化的操作。第三個來說就是安全性。最后就是最近流行的服務化架構、服務化治理,RPC框架是一個強力的支撐

---

rpc是一種概念,http也是rpc實現的一種方式。論復雜度,dubbo/hessian用起來是超級簡單的。最近用dubbo和hessian比較多,http的幾乎都被廢棄了。

至於為什么用,其實很簡單,業務場景不一樣。我最早的單位所有的代碼都在一個工程里,一次要發布幾百m的代碼。這種架構是非常有利於小程序的。但是我們為什么要應用rpc層呢,一個功能,一套代碼下來不就解決了么?我覺得有幾個好處:

1 靈活部署 2 解耦 至於為什么,當你用到的時候,你會體會。

系統做大了,肯定是需要做微服務的。 現在我們做電商就是這樣,單獨有一個訂單系統,支付系統,商品系統,用戶系統。都是分開部署,單獨上線的。 但我們交互是用HTTP接口來交互的,我想轉用RPC,但問題是我現在還沒發現為什么需要用RPC,我還沒能理解它的作用和意義。

用http交互其實就已經屬於rpc了。

---------

RPC:遠程過程調用。RPC的核心並不在於使用什么協議。RPC的目的是讓你在本地調用遠程的方法,而對你來說這個調用是透明的,你並不知道這個調用的方法是部署哪里。通過RPC能解耦服務,這才是使用RPC的真正目的。RPC的原理主要用到了動態代理模式,至於http協議,只是傳輸協議而已。簡單的實現可以參考spring remoting,復雜的實現可以參考dubbo。

--------

RPC是一個軟件結構概念,是構建分布式應用的理論基礎。就好比為啥你家可以用到發電廠發出來的電?是因為電是可以傳輸的。至於用銅線還是用鐵絲還是其他 種類的導線,也就是用http還是用其他協議的問題了。這個要看什么場景,對性能要求怎么樣。比如在java中的最基本的就是RMI技術,它是java原 生的應用層分布式技術。我們可以肯定的是在傳輸性能方面,RMI的性能是優於HTTP的。那為啥很少用到這個技術?那是因為用這個有很多局限性,首先它要 保證傳輸的兩端都要要用java實現,且兩邊需要有相同的對象類型和代理接口,不需要容器,但是加大了編程的難度,在應用內部的各個子系統之間還是會看到 他的身影,比如EJB就是基於rmi技術的。這就與目前的bs架構的軟件大相徑庭。用http必須要服務端位於http容器里面,這樣減少了網絡傳輸方面 的開發,只需要關注業務開發即可。所以在架構一個軟件的時候,不能一定根據需求選定技術。

2.spring的RMI就是基於二進制的方式傳輸的

簡單實現如下:

 

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 簡單的實現RPC 類似dubbo實現 用接口實現 要實現接口 也就是直接使用jdk的動態代理來實現
 */
public class SimpleRpc {

	public static void export(final Object service, int port) throws Exception {
		if (service == null)
			throw new IllegalArgumentException("service instance == null");
		if (port <= 0 || port > 65535)// 端口范圍0~65535
			throw new IllegalArgumentException("Invalid port " + port);
		System.out.println("Export service " + service.getClass().getName() + " on port " + port);
		ServerSocket server = new ServerSocket(port);
		while (true) {
			try {
				final Socket socket = server.accept();
				new Thread(new Runnable() {
					public void run() {
						try {
							try {
								ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
								try {
									String methodName = input.readUTF();// 接口方法名
									Class<?>[] parameterTypes = (Class<?>[]) input.readObject();// 接口與參數類型
									Object[] arguments = (Object[]) input.readObject();// 具體參數值
									ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());// 獲取回傳output
									try {
										// 通過java的反射,動態執行實現類service的方法
										Method method = service.getClass().getMethod(methodName, parameterTypes);
										Object result = method.invoke(service, arguments);
										// 將調用結果回傳給調用方
										output.writeObject(result);
									} catch (Throwable t) {
										output.writeObject(t);// 關閉
									} finally {
										output.close();// 關閉
									}
								} finally {
									input.close();// 關閉
								}
							} finally {
								socket.close();// 關閉
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}).start();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@SuppressWarnings("unchecked")
	public static <T> T refer(final Class<T> interfaceClass, final String host, final int port) throws Exception {
		if (interfaceClass == null)
			throw new IllegalArgumentException("Interface class == null");
		if (!interfaceClass.isInterface())
			throw new IllegalArgumentException("The " + interfaceClass.getName() + " must be interface class!");
		if (host == null || host.length() == 0)
			throw new IllegalArgumentException("Host == null!");
		if (port <= 0 || port > 65535)
			throw new IllegalArgumentException("Invalid port " + port);
		return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] { interfaceClass },
				new InvocationHandler() {
					public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
						Socket socket = new Socket(host, port);
						try {
							ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
							try {
								output.writeUTF(method.getName());
								output.writeObject(method.getParameterTypes());
								output.writeObject(arguments);
								ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
								try {
									Object result = input.readObject();
									if (result instanceof Throwable) {
										throw (Throwable) result;
									}
									return result;
								} finally {
									input.close();
								}
							} finally {
								output.close();
							}
						} finally {
							socket.close();
						}
					}
				});
	}

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM