您好,登錄后才能下訂單哦!
本篇內容介紹了“java Dubbo是做什么的”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
RPC,Remote Procedure Call 即遠程過程調用,遠程過程調用其實對標的是本地過程調用,本地過程調用你熟悉吧?
想想那青蔥歲月,你在大學趕著期末大作業,正在攻克圖書管理系統,你奮筆疾書瘋狂地敲擊鍵盤,實現了圖書借閱、圖書歸還等等模塊,你實現的一個個方法之間的調用就叫本地過程調用。
你要是和我說你實現圖書館里系統已經用了服務化,搞了遠程調用了,我只能和你說你有點東西。
簡單的說本機上內部的方法調用都可以稱為本地過程調用,而遠程過程調用實際上就指的是你本地調用了遠程機子上的某個方法,這就是遠程過程調用。
讓我們小結一下,大致上一個 RPC 框架需要做的就是約定要通信協議,序列化的格式、一些容錯機制、負載均衡策略、監控運維和一個注冊中心!
沒錯就是簡單的實現,上面我們在思考如何設計一個 RPC 框架的時候想了很多,那算是生產環境使用級別的功能需求了,我們這是 Demo,目的是突出 RPC框架重點功能 - 實現遠程調用。
所以啥七七八八的都沒,并且我用偽代碼來展示,其實也就是刪除了一些保護性和約束性的代碼,因為看起來太多了不太直觀,需要一堆 try-catch 啥的,因此我刪減了一些,直擊重點。
Let's Do It!
首先我們定義一個接口和一個簡單實現。
public interface AobingService { String hello(String name); } public class AobingServiceImpl implements AobingService { public String hello(String name) { return "Yo man Hello,I am" + name; } }
然后我們再來實現服務提供者暴露服務的功能。
public class AobingRpcFramework { public static void export(Object service, int port) throws Exception { ServerSocket server = new ServerSocket(port); while(true) { Socket socket = server.accept(); new Thread(new Runnable() { //反序列化 ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); String methodName = input.read(); //讀取方法名 Class<?>[] parameterTypes = (Class<?>[]) input.readObject(); //參數類型 Object[] arguments = (Object[]) input.readObject(); //參數 Method method = service.getClass().getMethod(methodName, parameterTypes); //找到方法 Object result = method.invoke(service, arguments); //調用方法 // 返回結果 ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); output.writeObject(result); }).start(); } } public static <T> T refer (Class<T> interfaceClass, String host, int port) throws Exception { 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); //指定 provider 的 ip 和端口 ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); output.write(method.getName()); //傳方法名 output.writeObject(method.getParameterTypes()); //傳參數類型 output.writeObject(arguments); //傳參數值 ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); Object result = input.readObject(); //讀取結果 return result; } }); } }
好了,這個 RPC 框架就這樣好了,是不是很簡單?就是調用者傳遞了方法名、參數類型和參數值,提供者接收到這樣參數之后調用對于的方法返回結果就好了!這就是遠程過程調用。
我們來看看如何使用
//服務提供者只需要暴露出接口 AobingService service = new AobingServiceImpl (); AobingRpcFramework.export(service, 2333); //服務調用者只需要設置依賴 AobingService service = AobingRpcFramework.refer(AobingService.class, "127.0.0.1", 2333); service.hello();
看起來好像好不錯喲,不過這很是簡陋,用作 demo 有助理解還是極好的!
接下來就來看看 Dubbo 吧!上正菜!
Dubbo 是阿里巴巴 2011年開源的一個基于 Java 的 RPC 框架,中間沉寂了一段時間,不過其他一些企業還在用 Dubbo 并自己做了擴展,比如當當網的 Dubbox,還有網易考拉的 Dubbok。
但是在 2017 年阿里巴巴又重啟了對 Dubbo 維護。在 2017 年榮獲了開源中國 2017 最受歡迎的中國開源軟件 Top 3。
在 2018 年和 Dubbox 進行了合并,并且進入 Apache 孵化器,在 2019 年畢業正式成為 Apache 頂級項目。
目前 Dubbo 社區主力維護的是 2.6.x 和 2.7.x 兩大版本,2.6.x 版本主要是 bug 修復和少量功能增強為準,是穩定版本。
而 2.7.x 是主要開發版本,更新和新增新的 feature 和優化,并且 2.7.5 版本的發布被 Dubbo 認為是里程碑式的版本發布,之后我們再做分析。
它實現了面向接口的代理 RPC 調用,并且可以配合 ZooKeeper 等組件實現服務注冊和發現功能,并且擁有負載均衡、容錯機制等。
我們先來看下官網的一張圖。
大的三層分別為 Business(業務層)、RPC 層、Remoting,并且還分為 API 層和 SPI 層。
分為大三層其實就是和我們知道的網絡分層一樣的意思,只有層次分明,職責邊界清晰才能更好的擴展。
而分 API 層和 SPI 層這是 Dubbo 成功的一點,采用微內核設計+SPI擴展,使得有特殊需求的接入方可以自定義擴展,做定制的二次開發。
接下來咱們再來看看每一層都是干嘛的。
Service,業務層,就是咱們開發的業務邏輯層。
Config,配置層,主要圍繞 ServiceConfig 和 ReferenceConfig,初始化配置信息。
Proxy,代理層,服務提供者還是消費者都會生成一個代理類,使得服務接口透明化,代理層做遠程調用和返回結果。
Register,注冊層,封裝了服務注冊和發現。
Cluster,路由和集群容錯層,負責選取具體調用的節點,處理特殊的調用要求和負責遠程調用失敗的容錯措施。
Monitor,監控層,負責監控統計調用時間和次數。
Portocol,遠程調用層,主要是封裝 RPC 調用,主要負責管理 Invoker,Invoker代表一個抽象封裝了的執行體,之后再做詳解。
Exchange,信息交換層,用來封裝請求響應模型,同步轉異步。
Transport,網絡傳輸層,抽象了網絡傳輸的統一接口,這樣用戶想用 Netty 就用 Netty,想用 Mina 就用 Mina。
Serialize,序列化層,將數據序列化成二進制流,當然也做反序列化。
我再稍微提一下 SPI(Service Provider Interface),是 JDK 內置的一個服務發現機制,它使得接口和具體實現完全解耦。我們只聲明接口,具體的實現類在配置中選擇。
具體的就是你定義了一個接口,然后在META-INF/services
目錄下放置一個與接口同名的文本文件,文件的內容為接口的實現類,多個實現類用換行符分隔。
這樣就通過配置來決定具體用哪個實現!
而 Dubbo SPI 還做了一些改進,篇幅有限留在之后再談。
上面我已經介紹了每個層到底是干嘛的,我們現在再來串起來走一遍調用的過程,加深你對 Dubbo 的理解,讓知識點串起來,由點及面來一波連連看。
首先 Provider 啟動,通過 Proxy 組件根據具體的協議 Protocol 將需要暴露出去的接口封裝成 Invoker,Invoker 是 Dubbo 一個很核心的組件,代表一個可執行體。
然后再通過 Exporter 包裝一下,這是為了在注冊中心暴露自己套的一層,然后將 Exporter 通過 Registry 注冊到注冊中心。 這就是整體服務暴露過程。
接著我們來看消費者調用流程(把服務者暴露的過程也在圖里展示出來了,這個圖其實算一個挺完整的流程圖了)。
首先消費者啟動會向注冊中心拉取服務提供者的元信息,然后調用流程也是從 Proxy 開始,畢竟都需要代理才能無感知。
Proxy 持有一個 Invoker 對象,調用 invoke 之后需要通過 Cluster 先從 Directory 獲取所有可調用的遠程服務的 Invoker 列表,如果配置了某些路由規則,比如某個接口只能調用某個節點的那就再過濾一遍 Invoker 列表。
剩下的 Invoker 再通過 LoadBalance 做負載均衡選取一個。然后再經過 Filter 做一些統計什么的,再通過 Client 做數據傳輸,比如用 Netty 來傳輸。
傳輸需要經過 Codec 接口做協議構造,再序列化。最終發往對應的服務提供者。
服務提供者接收到之后也會進行 Codec 協議處理,然后反序列化后將請求扔到線程池處理。某個線程會根據請求找到對應的 Exporter ,而找到 Exporter 其實就是找到了 Invoker,但是還會有一層層 Filter,經過一層層過濾鏈之后最終調用實現類然后原路返回結果。
“java Dubbo是做什么的”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。