分布式服務(wù)框架之遠程通訊技術(shù)及原理分析

在分布式服務(wù)框架中竭宰,一個最基礎(chǔ)的問題就是遠程服務(wù)是怎么通訊的空郊,在Java領(lǐng)域中有很多可實現(xiàn)遠程通訊的技術(shù)份招,例如:RMI、MINA狞甚、ESB锁摔、Burlap、Hessian哼审、SOAP谐腰、EJB和JMS等,這些名詞之間到底是些什么關(guān)系呢涩盾,它們背后到底是基于什么原理實現(xiàn)的呢十气,了解這些是實現(xiàn)分布式服務(wù)框架的基礎(chǔ)知識,而如果在性能上有高的要求的話春霍,那深入了解這些技術(shù)背后的機制就是必須的了砸西。

要實現(xiàn)網(wǎng)絡(luò)機器間的通訊,首先得來看看計算機系統(tǒng)網(wǎng)絡(luò)通信的基本原理终畅,在底層層面去看籍胯,網(wǎng)絡(luò)通信需要做的就是將流從一臺計算機傳輸?shù)搅硗庖慌_計算機,基于傳輸協(xié)議和網(wǎng)絡(luò)IO來實現(xiàn)离福,其中傳輸協(xié)議比較出名的有tcp杖狼、udp等等,tcp妖爷、udp都是在基于Socket概念上為某類應(yīng)用場景而擴展出的傳輸協(xié)議,網(wǎng)絡(luò)IO絮识,主要有bio绿聘、nio、aio三種方式次舌,所有的分布式應(yīng)用通訊都基于這個原理而實現(xiàn)熄攘,只是為了應(yīng)用的易用,各種語言通常都會提供一些更為貼近應(yīng)用易用的應(yīng)用層協(xié)議彼念。

歸根結(jié)底挪圾,企業(yè)應(yīng)用系統(tǒng)就是對數(shù)據(jù)的處理,而對于一個擁有多個子系統(tǒng)的企業(yè)應(yīng)用系統(tǒng)而言逐沙,它的基礎(chǔ)支撐無疑就是對消息的處理哲思。與對象不同,消息本質(zhì)上是一種數(shù)據(jù)結(jié)構(gòu)(當(dāng)然吩案,對象也可以看做是一種特殊的消息)棚赔,它包含消費者與服務(wù)雙方都能識別的數(shù)據(jù),這些數(shù)據(jù)需要在不同的進程(機器)之間進行傳遞,并可能會被多個完全不同的客戶端消費靠益。消息傳遞相較文件傳遞與遠程過程調(diào)用(RPC)而言丧肴,似乎更勝一籌,因為它具有更好的平臺無關(guān)性捆毫,并能夠很好地支持并發(fā)與異步調(diào)用闪湾。

對于Web Service與RESTful而言,則可以看做是消息傳遞技術(shù)的一種衍生或封裝绩卤。

我們常常運用的消息模式是Message Channel(消息通道)模式途样,如圖所示。

消息通道作為在客戶端(消費者濒憋,Consumer)與服務(wù)(生產(chǎn)者何暇,Producer)之間引入的間接層,可以有效地解除二者之間的耦合凛驮。只要實現(xiàn)規(guī)定雙方需要通信的消息格式裆站,以及處理消息的機制與時機,就可以做到消費者對生產(chǎn)者的“無知”黔夭。事實上宏胯,該模式可以支持多個生產(chǎn)者與消費者。例如本姥,我們可以讓多個生產(chǎn)者向消息通道發(fā)送消息肩袍,因為消費者對生產(chǎn)者的無知性,它不必考慮究竟是哪個生產(chǎn)者發(fā)來的消息婚惫。

雖然消息通道解除了生產(chǎn)者與消費者之間的耦合氛赐,使得我們可以任意地對生產(chǎn)者與消費者進行擴展,但它又同時引入了各自對消息通道的依賴先舷,因為它們必須知道通道資源的位置艰管。要解除這種對通道的依賴,可以考慮引入Lookup服務(wù)來查找該通道資源蒋川。例如牲芋,在JMS中就可以通過JNDI來獲取消息通道Queue。若要做到充分的靈活性捺球,可以將與通道相關(guān)的信息存儲到配置文件中街图,Lookup服務(wù)首先通過讀取配置文件來獲得通道。

消息通道通常以隊列的形式存在懒构,這種先進先出的數(shù)據(jù)結(jié)構(gòu)無疑最為適合這種處理消息的場景。微軟的MSMQ耘擂、IBM MQ胆剧、JBoss MQ以及開源的RabbitMQ、Apache ActiveMQ都通過隊列實現(xiàn)了Message Channel模式。因此秩霍,在選擇運用Message Channel模式時篙悯,更多地是要從質(zhì)量屬性的層面對各種實現(xiàn)了該模式的產(chǎn)品進行全方位的分析與權(quán)衡。例如铃绒,消息通道對并發(fā)的支持以及在性能上的表現(xiàn);消息通道是否充分地考慮了錯誤處理;對消息安全的支持;以及關(guān)于消息持久化鸽照、災(zāi)備(fail over)與集群等方面的支持。

因為通道傳遞的消息往往是一些重要的業(yè)務(wù)數(shù)據(jù)颠悬,一旦通道成為故障點或安全性的突破點矮燎,對系統(tǒng)就會造成災(zāi)難性的影響。

此處也順帶的提下jndi的機制赔癌,由于JNDI取決于具體的實現(xiàn)诞外,在這里只能是講解下jboss的jndi的實現(xiàn)了:

在將對象實例綁定到j(luò)boss jnp server后,當(dāng)遠程端采用context.lookup()方式獲取遠程對象實例并開始調(diào)用時灾票,jboss jndi的實現(xiàn)方法是從jnp server上獲取對象實例峡谊,將其序列化回本地,然后在本地進行反序列化刊苍,之后在本地進行類調(diào)用既们。

通過這個機制,就可以知道了正什,本地其實是必須有綁定到j(luò)boss上的對象實例的class的啥纸,否則反序列化的時候肯定就失敗了,而遠程通訊需要做到的是在遠程執(zhí)行某動作埠忘,并獲取到相應(yīng)的結(jié)果脾拆,可見純粹基于JNDI是無法實現(xiàn)遠程通訊的。

但JNDI也是實現(xiàn)分布式服務(wù)框架一個很關(guān)鍵的技術(shù)點莹妒,因為可以通過它來實現(xiàn)透明化的遠端和本地調(diào)用名船,就像ejb,另外它也是個很好的隱藏實際部署機制(就像datasource)等的方案旨怠。

一旦消息通道需要支持多個消費者時渠驼,就可能面臨兩種模型的選擇:拉模型與推模型。拉模型是由消息的消費者發(fā)起的鉴腻,主動權(quán)把握在消費者手中迷扇,它會根據(jù)自己的情況對生產(chǎn)者發(fā)起調(diào)用。如圖所示:

拉模型的另一種體現(xiàn)則由生產(chǎn)者在狀態(tài)發(fā)生變更時爽哎,通知消費者其狀態(tài)發(fā)生了改變蜓席。但得到通知的消費者卻會以回調(diào)方式,通過調(diào)用傳遞過來的消費者對象獲取更多細節(jié)消息课锌。

在基于消息的分布式系統(tǒng)中厨内,拉模型的消費者通常以Batch Job的形式祈秕,根據(jù)事先設(shè)定的時間間隔,定期偵聽通道的情況雏胃。一旦發(fā)現(xiàn)有消息傳遞進來请毛,就會轉(zhuǎn)而將消息傳遞給真正的處理器(也可以看做是消費者)處理消息,執(zhí)行相關(guān)的業(yè)務(wù)瞭亮。

推模型的主動權(quán)常常掌握在生產(chǎn)者手中方仿,消費者被動地等待生產(chǎn)者發(fā)出的通知,這就要求生產(chǎn)者必須了解消費者的相關(guān)信息统翩。如圖所示:

對于推模型而言仙蚜,消費者無需了解生產(chǎn)者。在生產(chǎn)者通知消費者時唆缴,傳遞的往往是消息(或事件)鳍征,而非生產(chǎn)者自身。同時面徽,生產(chǎn)者還可以根據(jù)不同的情況艳丛,注冊不同的消費者,又或者在封裝的通知邏輯中趟紊,根據(jù)不同的狀態(tài)變化氮双,通知不同的消費者。

兩種模型各有優(yōu)勢霎匈。拉模型的好處在于可以進一步解除消費者對通道的依賴戴差,通過后臺任務(wù)去定期訪問消息通道。壞處是需要引入一個單獨的服務(wù)進程铛嘱,以Schedule形式執(zhí)行暖释。而對于推模型而言,消息通道事實上會作為消費者觀察的主體墨吓,一旦發(fā)現(xiàn)消息進入球匕,就會通知消費者執(zhí)行對消息的處理。無論推模型帖烘,拉模型亮曹,對于消息對象而言,都可能采用類似Observer模式的機制秘症,實現(xiàn)消費者對生產(chǎn)者的訂閱照卦,因此這種機制通常又被稱為Publisher-Subscriber模式,如圖所示:

通常情況下乡摹,發(fā)布者和訂閱者都會被注冊到用于傳播變更的基礎(chǔ)設(shè)施(即消息通道)上役耕。發(fā)布者會主動地了解消息通道,使其能夠?qū)⑾l(fā)送到通道中;消息通道一旦接收到消息聪廉,會主動地調(diào)用注冊在通道中的訂閱者瞬痘,進而完成對消息內(nèi)容的消費氏义。

對于訂閱者而言,有兩種處理消息的方式图云。一種方式是廣播機制,這時消息通道中的消息在出列的同時邻邮,還需要復(fù)制消息對象竣况,將消息傳遞給多個訂閱者。例如筒严,有多個子系統(tǒng)都需要獲取從CRM系統(tǒng)傳來的客戶信息丹泉,并根據(jù)傳遞過來的客戶信息,進行相應(yīng)的處理鸭蛙。此時的消息通道又被稱為Propagation通道摹恨。另一種方式則屬于搶占機制,它遵循同步方式娶视,在同一時間只能有一個訂閱者能夠處理該消息晒哄。實現(xiàn)Publisher-Subscriber模式的消息通道會選擇當(dāng)前空閑的唯一訂閱者,并將消息出列肪获,并傳遞給訂閱者的消息處理方法寝凌。

目前,有許多消息中間件都能夠很好地支持Publisher-Subscriber模式孝赫,例如JMS接口規(guī)約中對于Topic對象提供的MessagePublisher與MessageSubscriber接口较木。RabbitMQ也提供了自己對該模式的實現(xiàn)。微軟的MSMQ雖然引入了事件機制青柄,可以在隊列收到消息時觸發(fā)事件伐债,通知訂閱者。但它并非嚴(yán)格意義上的Publisher-Subscriber模式實現(xiàn)致开。由微軟MVP Udi Dahan作為主要貢獻者的NServiceBus峰锁,則對MSMQ以及WCF做了進一層包裝,并能夠很好地實現(xiàn)這一模式喇喉。

無論是Message Channel模式祖今,還是Publisher-Subscriber模式,隊列在其中都扮演了舉足輕重的角色拣技。然而千诬,在企業(yè)應(yīng)用系統(tǒng)中,當(dāng)系統(tǒng)變得越來越復(fù)雜時膏斤,對性能的要求也會越來越高徐绑,此時對于系統(tǒng)而言,可能就需要支持同時部署多個隊列莫辨,并可能要求分布式部署不同的隊列傲茄。這些隊列可以根據(jù)定義接收不同的消息毅访,例如訂單處理的消息,日志信息盘榨,查詢?nèi)蝿?wù)消息等喻粹。這時,對于消息的生產(chǎn)者和消費者而言草巡,并不適宜承擔(dān)決定消息傳遞路徑的職責(zé)守呜。事實上,根據(jù)S單一職責(zé)原則山憨,這種職責(zé)分配也是不合理的查乒,它既不利于業(yè)務(wù)邏輯的重用,也會造成生產(chǎn)者郁竟、消費者與消息隊列之間的耦合玛迄,從而影響系統(tǒng)的擴展。

既然這三種對象(組件)都不宜承擔(dān)這樣的職責(zé)棚亩,就有必要引入一個新的對象專門負責(zé)傳遞路徑選擇的功能蓖议,這就是所謂的Message Router模式,如圖所示:

通過消息路由蔑舞,我們可以配置路由規(guī)則指定消息傳遞的路徑拒担,以及指定具體的消費者消費對應(yīng)的生產(chǎn)者。例如指定路由的關(guān)鍵字攻询,并由它來綁定具體的隊列與指定的生產(chǎn)者(或消費者)从撼。路由的支持提供了消息傳遞與處理的靈活性,也有利于提高整個系統(tǒng)的消息處理能力钧栖。同時低零,路由對象有效地封裝了尋找與匹配消息路徑的邏輯,就好似一個調(diào)停者(Meditator)拯杠,負責(zé)協(xié)調(diào)消息掏婶、隊列與路徑尋址之間關(guān)系。

遠程服務(wù)通訊潭陪,需要達到的目標(biāo)是在一臺計算機發(fā)起請求雄妥,另外一臺機器在接收到請求后進行相應(yīng)的處理并將結(jié)果返回給請求端,這其中又會有諸如one way request依溯、同步請求老厌、異步請求等等請求方式,按照網(wǎng)絡(luò)通信原理黎炉,需要實現(xiàn)這個需要做的就是將請求轉(zhuǎn)換成流枝秤,通過傳輸協(xié)議傳輸至遠端,遠端計算機在接收到請求的流后進行處理慷嗜,處理完畢后將結(jié)果轉(zhuǎn)化為流淀弹,并通過傳輸協(xié)議返回給調(diào)用端丹壕。

原理是這樣的,但為了應(yīng)用的方便薇溃,業(yè)界推出了很多基于此原理之上的應(yīng)用級的協(xié)議菌赖,使得大家可以不用去直接操作這么底層的東西,通常應(yīng)用級的遠程通信協(xié)議會提供:

1.為了避免直接做流操作這么麻煩沐序,提供一種更加易用或貼合語言的標(biāo)準(zhǔn)傳輸格式;

2.網(wǎng)絡(luò)通信機制的實現(xiàn)盏袄,就是替你完成了將傳輸格式轉(zhuǎn)化為流,通過某種傳輸協(xié)議傳輸至遠端計算機薄啥,遠端計算機在接收到流后轉(zhuǎn)化為傳輸格式,并進行存儲或以某種方式通知遠端計算機逛尚。

所以在學(xué)習(xí)應(yīng)用級的遠程通信協(xié)議時垄惧,我們可以帶著這幾個問題進行學(xué)習(xí):

1.傳輸?shù)臉?biāo)準(zhǔn)格式是什么?

2.怎么樣將請求轉(zhuǎn)化為傳輸?shù)牧?

3.怎么接收和處理流?

4.傳輸協(xié)議是?

不過應(yīng)用級的遠程通信協(xié)議并不會在傳輸協(xié)議上做什么多大的改進,主要是在流操作方面绰寞,讓應(yīng)用層生成流和處理流的這個過程更加的貼合所使用的語言或標(biāo)準(zhǔn)到逊,至于傳輸協(xié)議則通常都是可選的,在java領(lǐng)域中知名的有:RMI滤钱、XML-RPC觉壶、Binary-RPC、SOAP件缸、CORBA铜靶、JMS、HTTP他炊,來具體的看看這些遠程通信的應(yīng)用級協(xié)議争剿。

RMI是個典型的為java定制的遠程通信協(xié)議,我們都知道痊末,在single vm中蚕苇,我們可以通過直接調(diào)用java object instance來實現(xiàn)通信,那么在遠程通信時凿叠,如果也能按照這種方式當(dāng)然是最好了涩笤,這種遠程通信的機制成為RPC(Remote Procedure Call),RMI正是朝著這個目標(biāo)而誕生的盒件。

RMI采用stubs 和 skeletons 來進行遠程對象(remote object)的通訊蹬碧。stub 充當(dāng)遠程對象的客戶端代理,有著和遠程對象相同的遠程接口履恩,遠程對象的調(diào)用實際是通過調(diào)用該對象的客戶端代理對象stub來完成的锰茉,通過該機制RMI就好比它是本地工作,采用tcp/ip協(xié)議切心,客戶端直接調(diào)用服務(wù)端上的一些方法飒筑。優(yōu)點是強類型片吊,編譯期可檢查錯誤,缺點是只能基于JAVA語言协屡,客戶機與服務(wù)器緊耦合俏脊。

來看下基于RMI的一次完整的遠程通信過程的原理:

1.客戶端發(fā)起請求,請求轉(zhuǎn)交至RMI客戶端的stub類;

2.stub類將請求的接口肤晓、方法爷贫、參數(shù)等信息進行序列化;

3.基于socket將序列化后的流傳輸至服務(wù)器端;

4.服務(wù)器端接收到流后轉(zhuǎn)發(fā)至相應(yīng)的skelton類;

5.skelton類將請求的信息反序列化后調(diào)用實際的處理類;

6.處理類處理完畢后將結(jié)果返回給skelton類;

7.Skelton類將結(jié)果序列化,通過socket將流傳送給客戶端的stub;

8.stub在接收到流后反序列化补憾,將反序列化后的Java Object返回給調(diào)用者漫萄。

根據(jù)原理來回答下之前學(xué)習(xí)應(yīng)用級協(xié)議帶著的幾個問題:

1.傳輸?shù)臉?biāo)準(zhǔn)格式是什么?是Java ObjectStream。

2.怎么樣將請求轉(zhuǎn)化為傳輸?shù)牧?基于Java串行化機制將請求的java object信息轉(zhuǎn)化為流盈匾。

3.怎么接收和處理流?根據(jù)采用的協(xié)議啟動相應(yīng)的監(jiān)聽端口腾务,當(dāng)有流進入后基于Java串行化機制將流進行反序列化,并根據(jù)RMI協(xié)議獲取到相應(yīng)的處理對象信息削饵,進行調(diào)用并處理岩瘦,處理完畢后的結(jié)果同樣基于java串行化機制進行返回。

4.傳輸協(xié)議是?Socket窿撬。

RPC使用C/S方式启昧,采用http協(xié)議,發(fā)送請求到服務(wù)器劈伴,等待服務(wù)器返回結(jié)果密末。這個請求包括一個參數(shù)集和一個文本集,通常形成“classname.methodname”形式跛璧。優(yōu)點是跨語言跨平臺苏遥,C端、S端有更大的獨立性赡模,缺點是不支持對象田炭,無法在編譯器檢查錯誤,只能在運行期檢查漓柑。

XML-RPC也是一種和RMI類似的遠程調(diào)用的協(xié)議教硫,它和RMI的不同之處在于它以標(biāo)準(zhǔn)的xml格式來定義請求的信息(請求的對象、方法辆布、參數(shù)等)瞬矩,這樣的好處是什么呢,就是在跨語言通訊的時候也可以使用锋玲。

來看下XML-RPC協(xié)議的一次遠程通信過程:

1.客戶端發(fā)起請求景用,按照XML-RPC協(xié)議將請求信息進行填充;

2.填充完畢后將xml轉(zhuǎn)化為流,通過傳輸協(xié)議進行傳輸;

3.接收到在接收到流后轉(zhuǎn)換為xml,按照XML-RPC協(xié)議獲取請求的信息并進行處理;

4.處理完畢后將結(jié)果按照XML-RPC協(xié)議寫入xml中并返回伞插。

同樣來回答問題:

1.傳輸?shù)臉?biāo)準(zhǔn)格式是?標(biāo)準(zhǔn)格式的XML割粮。

2.怎么樣將請求轉(zhuǎn)化為傳輸?shù)牧?將XML轉(zhuǎn)化為流。

3.怎么接收和處理流?通過監(jiān)聽的端口獲取到請求的流媚污,轉(zhuǎn)化為XML舀瓢,并根據(jù)協(xié)議獲取請求的信息,進行處理并將結(jié)果寫入XML中返回耗美。

4.傳輸協(xié)議是?Http京髓。

Binary-RPC看名字就知道和XML-RPC是差不多的了,不同之處僅在于傳輸?shù)臉?biāo)準(zhǔn)格式由XML轉(zhuǎn)為了二進制的格式商架。

同樣來回答問題:

1.傳輸?shù)臉?biāo)準(zhǔn)格式是?標(biāo)準(zhǔn)格式的二進制文件堰怨。

2.怎么樣將請求轉(zhuǎn)化為傳輸?shù)牧?將二進制格式文件轉(zhuǎn)化為流。

3.怎么接收和處理流?通過監(jiān)聽的端口獲取到請求的流蛇摸,轉(zhuǎn)化為二進制文件诚些,根據(jù)協(xié)議獲取請求的信息,進行處理并將結(jié)果寫入XML中返回皇型。

4.傳輸協(xié)議是?Http。

SOAP原意為Simple Object Access Protocol砸烦,是一個用于分布式環(huán)境的弃鸦、輕量級的、基于XML進行信息交換的通信協(xié)議幢痘,可以認為SOAP是XML RPC的高級版唬格,兩者的原理完全相同,都是http+XML颜说,不同的僅在于兩者定義的XML規(guī)范不同购岗,SOAP也是Webservice采用的服務(wù)調(diào)用協(xié)議標(biāo)準(zhǔn),因此在此就不多加闡述了门粪。

Web Service提供的服務(wù)是基于web容器的喊积,底層使用http協(xié)議,類似一個遠程的服務(wù)提供者玄妈,比如天氣預(yù)報服務(wù)乾吻,對各地客戶端提供天氣預(yù)報,是一種請求應(yīng)答的機制拟蜻,是跨系統(tǒng)跨平臺的绎签。就是通過一個servlet,提供服務(wù)出去酝锅。

首先客戶端從服務(wù)器獲得WebService的WSDL诡必,同時在客戶端生成一個代理類(Proxy Class),這個代理類負責(zé)與WebService服務(wù)器進行Request和Response搔扁。當(dāng)一個數(shù)據(jù)(XML格式的)被封裝成SOAP格式的數(shù)據(jù)流發(fā)送到服務(wù)器端的時候爸舒,就會生成一個進程對象并且把接收到這個Request的SOAP包進行解析蟋字,然后對事物進行處理,處理結(jié)束以后再對這個計算結(jié)果進行SOAP包裝碳抄,然后把這個包作為一個Response發(fā)送給客戶端的代理類(Proxy Class)泰涂,同樣地蔬浙,這個代理類也對這個SOAP包進行解析處理,繼而進行后續(xù)操作。這就是WebService的一個運行過程浪讳。

Web Service大體上分為5個層次:

1.Http傳輸信道;

2.XML的數(shù)據(jù)格式;

3.SOAP封裝格式;

4.WSDL的描述方式;

5.UDDI UDDI是一種目錄服務(wù),企業(yè)可以使用它對Webservices進行注冊和搜索;

JMS是實現(xiàn)java領(lǐng)域遠程通信的一種手段和方法窜护,基于JMS實現(xiàn)遠程通信時和RPC是不同的睡腿,雖然可以做到RPC的效果,但因為不是從協(xié)議級別定義的爷光,因此我們不認為JMS是個RPC協(xié)議垫竞,但它確實是個遠程通信協(xié)議,在其他的語言體系中也存在著類似JMS的東西蛀序,可以統(tǒng)一的將這類機制稱為消息機制欢瞪,而消息機制呢,通常是高并發(fā)徐裸、分布式領(lǐng)域推薦的一種通信機制遣鼓,這里的主要一個問題是容錯。

JMS是Java的消息服務(wù)重贺,JMS的客戶端之間可以通過JMS服務(wù)進行異步的消息傳輸骑祟。JMS支持兩種消息模型:Point-to-Point(P2P)和Publish/Subscribe(Pub/Sub),即點對點和發(fā)布訂閱模型气笙。

來看JMS中的一次遠程通信的過程:

1.客戶端將請求轉(zhuǎn)化為符合JMS規(guī)定的Message;

2.通過JMS API將Message放入JMS Queue或Topic中;

3.如為JMS Queue次企,則發(fā)送中相應(yīng)的目標(biāo)Queue中,如為Topic潜圃,則發(fā)送給訂閱了此Topic的JMS Queue缸棵。

4.處理端則通過輪訓(xùn)JMS Queue,來獲取消息谭期,接收到消息后根據(jù)JMS協(xié)議來解析Message并處理蛉谜。

同樣來回答問題:

1.傳輸?shù)臉?biāo)準(zhǔn)格式是?JMS規(guī)定的Message。

2.怎么樣將請求轉(zhuǎn)化為傳輸?shù)牧?將參數(shù)信息放入Message中即可崇堵。

3.怎么接收和處理流?輪訓(xùn)JMSQueue來接收Message型诚,接收到后進行處理,處理完畢后仍然是以Message的方式放入Queue中發(fā)送或Multicast鸳劳。

4.傳輸協(xié)議是?不限狰贯。

基于JMS也是常用的實現(xiàn)遠程異步調(diào)用的方法之一。

1.RPC跨語言,而RMI只支持Java涵紊。

2.RMI調(diào)用遠程對象方法傍妒,允許方法返回Java對象以及基本數(shù)據(jù)類型,而RPC不支持對象的概念摸柄,傳送到RPC服務(wù)的消息由外部數(shù)據(jù)表示

(External Data Representation, XDR) 語言表示颤练,這種語言抽象了字節(jié)序類和數(shù)據(jù)類型結(jié)構(gòu)之間的差異。只有由

XDR 定義的數(shù)據(jù)類型才能被傳遞驱负,可以說 RMI 是面向?qū)ο蠓绞降腏ava RPC嗦玖。

3.在方法調(diào)用上,RMI中跃脊,遠程接口使每個遠程方法都具有方法簽名宇挫。如果一個方法在服務(wù)器上執(zhí)行,但是沒有相匹配的簽名被添加到這個遠程接口上酪术,那么這個新方法就不能被RMI客戶方所調(diào)用器瘪。在RPC中,當(dāng)一個請求到達RPC服務(wù)器時绘雁,這個請求就包含了一個參數(shù)集和一個文本值橡疼,通常形成“classname.methodname”的形式。這就向RPC服務(wù)器表明庐舟,被請求的方法在為

“classname”的類中欣除,名叫“methodname”。然后RPC服務(wù)器就去搜索與之相匹配的類和方法继阻,并把它作為那種方法參數(shù)類型的輸入。這里的參數(shù)類型是與RPC請求中的類型是匹配的废酷。一旦匹配成功瘟檩,這個方法就被調(diào)用了,其結(jié)果被編碼后返回客戶方澈蟆。

4.RPC本身沒有規(guī)范,但基本的工作機制是一樣的墨辛,即:serialization/deserialization+stub+skeleton,寬泛的講趴俘,只要能實現(xiàn)遠程調(diào)用睹簇,都是RPC,如:rmi.net-remoting ws/soap/rest hessian xmlrpc thrift potocolbuffer寥闪。

5.在Java里提供了完整的sockets通訊接口太惠,但sockets要求客戶端和服務(wù)端必須進行應(yīng)用級協(xié)議的編碼交換數(shù)據(jù),采用sockets是非常麻煩的疲憋。一個代替Sockets的協(xié)議是RPC(RemoteProcedure Call), 它抽象出了通訊接口用于過程調(diào)用凿渊,使得編程者調(diào)用一個遠程過程和調(diào)用本地過程同樣方便。RPC系統(tǒng)采用XDR來編碼遠程調(diào)用的參數(shù)和返回值。但RPC并不支持對象埃脏,所以搪锣,面向?qū)ο蟮倪h程調(diào)用RMI(Remote Method Invocation)成為必然選擇。采用RMI彩掐,調(diào)用遠程對象和調(diào)用本地對象同樣方便构舟。RMI 采用JRMP(Java RemoteMethod Protocol)通訊協(xié)議,是構(gòu)建在TCP/IP協(xié)議上的一種遠程調(diào)用方法堵幽。

1.采用JMS服務(wù)狗超,對象是在物理上被異步從網(wǎng)絡(luò)的某個JVM 上直接移動到另一個JVM 上(是消息通知機制),而RMI對象是綁定在本地JVM

中谐檀,只有函數(shù)參數(shù)和返回值是通過網(wǎng)絡(luò)傳送的(是請求應(yīng)答機制)抡谐。

2.RMI一般都是同步的,也就是說桐猬,當(dāng)client調(diào)用Server的一個方法的時候麦撵,需要等到對方的返回,才能繼續(xù)執(zhí)行client端溃肪,這個過程調(diào)用本地方法感覺上是一樣的免胃,這也是RMI的一個特點。JMS一般只是一個點發(fā)出一個Message到Message Server,發(fā)出之后一般不會關(guān)心誰用了這個message惫撰。所以羔沙,一般RMI的應(yīng)用是緊耦合,JMS的應(yīng)用相對來說是松散耦合應(yīng)用厨钻。

RMI是在tcp協(xié)議上傳遞可序列化的java對象扼雏,只能用在java虛擬機上,綁定語言夯膀,客戶端和服務(wù)端都必須是java诗充。webservice沒有這個限制,webservice是在http協(xié)議上傳遞xml文本文件诱建,與語言和平臺無關(guān)蝴蜓。

Webservice專注于遠程服務(wù)調(diào)用,jms專注于信息交換俺猿。

大多數(shù)情況下Webservice是兩系統(tǒng)間的直接交互(Consumer Producer)茎匠,而大多數(shù)情況下jms是三方系統(tǒng)交互(Consumer Producer)。當(dāng)然押袍,JMS也可以實現(xiàn)request-response模式的通信诵冒,只要Consumer或Producer其中一方兼任broker即可。

JMS可以做到異步調(diào)用完全隔離了客戶端和服務(wù)提供者谊惭,能夠抵御流量洪峰;WebService服務(wù)通常為同步調(diào)用造烁,需要有復(fù)雜的對象轉(zhuǎn)換否过,相比SOAP,現(xiàn)在JSON惭蟋,rest都是很好的http架構(gòu)方案;

JMS是java平臺上的消息規(guī)范苗桂。一般jms消息不是一個xml,而是一個java對象告组,很明顯煤伟,jms沒考慮異構(gòu)系統(tǒng),說白了木缝,JMS就沒考慮非java的東西便锨。但是好在現(xiàn)在大多數(shù)的jms provider(就是JMS的各種實現(xiàn)產(chǎn)品)都解決了異構(gòu)問題。相比WebService的跨平臺各有千秋吧我碟。

目前java領(lǐng)域可用于實現(xiàn)遠程通訊的框架或library放案,知名的有:JBoss-Remoting、Spring-Remoting矫俺、Hessian吱殉、Burlap、XFire(Axis)厘托、ActiveMQ友雳、Mina、Mule铅匹、EJB3等等押赊,來對每種做個簡單的介紹和評價,其實呢包斑,要做分布式服務(wù)框架流礁,這些東西都是要有非常深刻的了解的,因為分布式服務(wù)框架其實是包含了解決分布式領(lǐng)域以及應(yīng)用層面領(lǐng)域兩方面問題的罗丰。

當(dāng)然神帅,你也可以自己根據(jù)遠程網(wǎng)絡(luò)通信原理(transport protocol+Net IO)去實現(xiàn)自己的通訊框架或library。

那么在了解這些遠程通訊的框架或library時丸卷,會帶著什么問題去學(xué)習(xí)呢?

1.是基于什么協(xié)議實現(xiàn)的?

2.怎么發(fā)起請求?

3.怎么將請求轉(zhuǎn)化為符合協(xié)議的格式的?

4.使用什么傳輸協(xié)議傳輸?

5.響應(yīng)端基于什么機制來接收請求?

6.怎么將流還原為傳輸格式的?

7.處理完畢后怎么回應(yīng)?

Spring-remoting是Spring提供java領(lǐng)域的遠程通訊框架枕稀,基于此框架询刹,同樣也可以很簡單的將普通的spring bean以某種遠程協(xié)議的方式來發(fā)布谜嫉,同樣也可以配置spring bean為遠程調(diào)用的bean。

1.是基于什么協(xié)議實現(xiàn)的?作為一個遠程通訊的框架凹联,Spring通過集成多種遠程通訊的library沐兰,從而實現(xiàn)了對多種協(xié)議的支持,例如rmi蔽挠、http+io住闯、xml-rpc瓜浸、binary-rpc等。

2.怎么發(fā)起請求?在Spring中比原,由于其對于遠程調(diào)用的bean采用的是proxy實現(xiàn)插佛,發(fā)起請求完全是通過服務(wù)接口調(diào)用的方式。

3.怎么將請求轉(zhuǎn)化為符合協(xié)議的格式的?Spring按照協(xié)議方式將請求的對象信息轉(zhuǎn)化為流量窘,例如Spring Http

Invoker是基于Spring自己定義的一個協(xié)議來實現(xiàn)的雇寇,傳輸協(xié)議上采用的為http,請求信息是基于java串行化機制轉(zhuǎn)化為流進行傳輸蚌铜。

4.使用什么傳輸協(xié)議傳輸?支持多種傳輸協(xié)議锨侯,例如rmi、http等等冬殃。

5.響應(yīng)端基于什么機制來接收請求?響應(yīng)端遵循協(xié)議方式來接收請求囚痴,對于使用者而言,則只需通過spring的配置方式將普通的spring

bean配置為響應(yīng)端或者說提供服務(wù)端审葬。

6.怎么將流還原為傳輸格式的?按照協(xié)議方式來進行還原深滚。

7.處理完畢后怎么回應(yīng)?處理完畢后直接返回即可耳璧,spring-remoting將根據(jù)協(xié)議方式來做相應(yīng)的序列化。

Hessian是由caucho提供的一個基于binary-RPC實現(xiàn)的遠程通訊library旨枯。

1.是基于什么協(xié)議實現(xiàn)的?基于Binary-RPC協(xié)議實現(xiàn)。

2.怎么發(fā)起請求?需通過Hessian本身提供的API來發(fā)起請求攀隔。

3.怎么將請求轉(zhuǎn)化為符合協(xié)議的格式的?Hessian通過其自定義的串行化機制將請求信息進行序列化皂贩,產(chǎn)生二進制流明刷。

4.使用什么傳輸協(xié)議傳輸?Hessian基于Http協(xié)議進行傳輸。

5.響應(yīng)端基于什么機制來接收請求?響應(yīng)端根據(jù)Hessian提供的API來接收請求满粗。

6.怎么將流還原為傳輸格式的?Hessian根據(jù)其私有的串行化機制來將請求信息進行反序列化辈末,傳遞給使用者時已是相應(yīng)的請求信息對象了映皆。

7.處理完畢后怎么回應(yīng)?處理完畢后直接返回,hessian將結(jié)果對象進行序列化组去,傳輸至調(diào)用端步淹。

Burlap也是有caucho提供诚撵,它和hessian的不同在于键闺,它是基于XML-RPC協(xié)議的辛燥。

1.是基于什么協(xié)議實現(xiàn)的?基于XML-RPC協(xié)議實現(xiàn)。

2.怎么發(fā)起請求?根據(jù)Burlap提供的API畅铭。

3.怎么將請求轉(zhuǎn)化為符合協(xié)議的格式的?將請求信息轉(zhuǎn)化為符合協(xié)議的XML格式勃蜘,轉(zhuǎn)化為流進行傳輸缭贡。

4.使用什么傳輸協(xié)議傳輸?Http協(xié)議。

5.響應(yīng)端基于什么機制來接收請求?監(jiān)聽Http請求谍失。

6.怎么將流還原為傳輸格式的?根據(jù)XML-RPC協(xié)議進行還原莹汤。

7.處理完畢后怎么回應(yīng)?返回結(jié)果寫入XML中,由Burlap返回至調(diào)用端抹竹。

XFire止潮、Axis是Webservice的實現(xiàn)框架,WebService可算是一個完整的SOA架構(gòu)實現(xiàn)標(biāo)準(zhǔn)了袄琳,因此采用XFire唆樊、Axis這些也就意味著是采用webservice方式了橘沥。

是基于什么協(xié)議實現(xiàn)的?基于SOAP協(xié)議夯秃。

怎么發(fā)起請求?獲取到遠端service的proxy后直接調(diào)用。

怎么將請求轉(zhuǎn)化為符合協(xié)議的格式的?將請求信息轉(zhuǎn)化為遵循SOAP協(xié)議的XML格式堤舒,由框架轉(zhuǎn)化為流進行傳輸哺呜。

使用什么傳輸協(xié)議傳輸?Http協(xié)議。

響應(yīng)端基于什么機制來接收請求?監(jiān)聽Http請求国撵。

怎么將流還原為傳輸格式的?根據(jù)SOAP協(xié)議進行還原介牙。

處理完畢后怎么回應(yīng)?返回結(jié)果寫入XML中澳厢,由框架返回至調(diào)用端。

ActiveMQ是JMS的實現(xiàn)线得,基于JMS這類消息機制實現(xiàn)遠程通訊是一種不錯的選擇贯钩,畢竟消息機制本身的功能使得基于它可以很容易的去實現(xiàn)同步/異步/單向調(diào)用等办素,而且消息機制從容錯角度上來說也是個不錯的選擇摸屠,這是Erlang能夠做到容錯的重要基礎(chǔ)。

1.是基于什么協(xié)議實現(xiàn)的?基于JMS協(xié)議檩咱。

2.怎么發(fā)起請求?遵循JMS API發(fā)起請求胯舷。

3.怎么將請求轉(zhuǎn)化為符合協(xié)議的格式的?不太清楚桑嘶,猜想應(yīng)該是二進制流。

4.使用什么傳輸協(xié)議傳輸?支持多種傳輸協(xié)議讨便,例如socket、http等等伴找。

5.響應(yīng)端基于什么機制來接收請求?監(jiān)聽符合協(xié)議的端口技矮。

6.怎么將流還原為傳輸格式的?同問題3殊轴。

7.處理完畢后怎么回應(yīng)?遵循JMS API生成消息旁理,并寫入JMS Queue中。

Mina是Apache提供的通訊框架淹接,在之前一直沒有提到網(wǎng)絡(luò)IO這塊叛溢,之前提及的框架或library基本都是基于BIO的楷掉,而Mina是采用NIO的,NIO在并發(fā)量增長時對比BIO而言會有明顯的性能提升斑鸦,而java性能的提升草雕,與其NIO這塊與OS的緊密結(jié)合是有不小的關(guān)系的墩虹。

1.是基于什么協(xié)議實現(xiàn)的?基于純粹的Socket+NIO。

2.怎么發(fā)起請求?通過Mina提供的Client API旬昭。

3.怎么將請求轉(zhuǎn)化為符合協(xié)議的格式的?Mina遵循java串行化機制對請求對象進行序列化问拘。

4.使用什么傳輸協(xié)議傳輸?支持多種傳輸協(xié)議,例如socket绪杏、http等等或油。

5.響應(yīng)端基于什么機制來接收請求?以NIO的方式監(jiān)聽協(xié)議端口顶岸。

6.怎么將流還原為傳輸格式的?遵循java串行化機制對請求對象進行反序列化辖佣。

7.處理完畢后怎么回應(yīng)?遵循Mina API進行返回搓逾。

MINA是NIO方式的,因此支持異步調(diào)用是毫無懸念的世蔗。

RPC(Remote Procedure Call)是一種遠程調(diào)用協(xié)議污淋,簡單地說就是能使應(yīng)用像調(diào)用本地方法一樣的調(diào)用遠程的過程或服務(wù)余掖,可以應(yīng)用在分布式服務(wù)盐欺、分布式計算、遠程服務(wù)調(diào)用等許多場景魔种。說起 RPC 大家并不陌生务嫡,業(yè)界有很多開源的優(yōu)秀 RPC 框架漆改,例如 Dubbo挫剑、Thrift、gRPC愉棱、Hprose 等等。下面先簡單介紹一下 RPC 與常用遠程調(diào)用方式的特點艾岂,以及一些優(yōu)秀的開源 RPC 框架王浴。

RPC與其它遠程調(diào)用方式比較梅猿,RPC 與 HTTP袱蚓、RMI、Web Service 都能完成遠程調(diào)用体斩,但是實現(xiàn)方式和側(cè)重點各有不同硕勿。

HTTP(HyperText Transfer Protocol)是應(yīng)用層通信協(xié)議枫甲,使用標(biāo)準(zhǔn)語義訪問指定資源(圖片想幻、接口等),網(wǎng)絡(luò)中的中轉(zhuǎn)服務(wù)器能識別協(xié)議內(nèi)容闹究。HTTP 協(xié)議是一種資源訪問協(xié)議渣淤,通過 HTTP 協(xié)議可以完成遠程請求并返回請求結(jié)果吉嫩。

HTTP的優(yōu)點是簡單自娩、易用、可理解性強且語言無關(guān)脐彩,在遠程服務(wù)調(diào)用中包括微博有著廣泛應(yīng)用惠奸。HTTP 的缺點是協(xié)議頭較重佛南,一般請求到具體服務(wù)器的鏈路較長,可能會有 DNS 解析愧怜、Nginx 代理等妈拌。

RPC是一種協(xié)議規(guī)范尘分,可以把 HTTP 看作是一種RPC 的實現(xiàn)培愁,也可以把 HTTP 作為 RPC 的傳輸協(xié)議來應(yīng)用缓窜。RPC 服務(wù)的自動化程度比較高禾锤,能夠?qū)崿F(xiàn)強大的服務(wù)治理功能,和語言結(jié)合更友好倡鲸,性能也十分優(yōu)秀峭状。與 HTTP 相比优床,RPC 的缺點就是相對復(fù)雜誓焦,學(xué)習(xí)成本稍高。

1.RMI(Remote Method Invocation)是指 Java 語言中的遠程方法調(diào)用启摄,RMI 中的每個方法都具有方法簽名幽钢,RMI 客戶端和服務(wù)器端通過方法簽名進行遠程方法調(diào)用匪燕。RMI 只能在 Java 語言中使用帽驯,可以把 RMI 看作面向?qū)ο蟮?Java RPC。

2.說到這里利凑,順便給大家推薦一個Java方面中高級程度的架構(gòu)交流學(xué)習(xí)群:650385180哀澈,里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring度气,MyBatis磷籍,Netty源碼分析院领,高并發(fā)、高性能汪诉、分布式扒寄、微服務(wù)架構(gòu)的原理拟烫,JVM性能優(yōu)化這些成為架構(gòu)師必備的知識體系硕淑。還能領(lǐng)取免費的學(xué)習(xí)資源,相信對于已經(jīng)工作和遇到技術(shù)瓶頸的碼友公条,在這個群里會有你需要的內(nèi)容迂曲。

Web Service 是一種基于 Web 進行服務(wù)發(fā)布路捧、查詢杰扫、調(diào)用的架構(gòu)方式,重點在于服務(wù)的管理與使用佳遣。Web Service 一般通過 WSDL 描述服務(wù)苍日,使用 SOAP通過 HTTP 調(diào)用服務(wù)。

RPC是一種遠程訪問協(xié)議笨觅,而 Web Service 是一種體系結(jié)構(gòu)耕腾,Web Service 也可以通過 RPC 來進行服務(wù)調(diào)用扫俺,因此 Web Service 更適合同一個 RPC 框架進行比較狼纬。當(dāng) RPC 框架提供了服務(wù)的發(fā)現(xiàn)與管理疗琉,并使用 HTTP 作為傳輸協(xié)議時,其實就是 Web Service凑耻。

相對 Web Service香浩,RPC 框架可以對服務(wù)進行更細粒度的治理,包括流量控制呀非、SLA 管理等岸裙,在微服務(wù)化降允、分布式計算方面有更大的優(yōu)勢剧董。

RPC可基于 HTTP 或 TCP 協(xié)議破停,Web Service 就是基于 HTTP 協(xié)議的 RPC真慢,它具有良好的跨平臺性黑界,但其性能卻不如基于 TCP 協(xié)議的 RPC朗鸠。會兩方面會直接影響 RPC 的性能,一是傳輸方式胎挎,二是序列化犹菇。

眾所周知项栏,TCP 是傳輸層協(xié)議沼沈,HTTP 是應(yīng)用層協(xié)議,而傳輸層較應(yīng)用層更加底層芽腾,在數(shù)據(jù)傳輸方面摊滔,越底層越快艰躺,因此腺兴,在一般情況下廉侧,TCP 一定比 HTTP 快段誊。

在遠程通訊領(lǐng)域中连舍,涉及的知識點還是相當(dāng)?shù)亩嗟难糖疲缬校和ㄐ艆f(xié)議(Socket/tcp/http/udp/rmi/xml-rpc etc.)参滴、消息機制砾赔、網(wǎng)絡(luò)IO(BIO/NIO/AIO)青灼、MultiThread、本地調(diào)用與遠程調(diào)用的透明化方案(涉及Java Classloader杂拨、Dynamic Proxy专普、Unit Test etc.)、異步與同步調(diào)用弹沽、網(wǎng)絡(luò)通信處理機制(自動重連檀夹、廣播筋粗、異常、池處理等等)炸渡、Java Serialization (各種協(xié)議的私有序列化機制等)娜亿、各種框架的實現(xiàn)原理(傳輸格式蚌堵、如何將傳輸格式轉(zhuǎn)化為流的买决、如何將請求信息轉(zhuǎn)化為傳輸格式的、如何接收流的吼畏、如何將流還原為傳輸格式的等等)督赤,要精通其中的哪些東西,得根據(jù)實際需求來決定了泻蚊,只有在了解了原理的情況下才能很容易的做出選擇够挂,甚至可以根據(jù)需求做私有的遠程通訊協(xié)議,對于從事分布式服務(wù)平臺或開發(fā)較大型的分布式應(yīng)用的人而言藕夫,我覺得至少上面提及的知識點是需要比較了解的孽糖。

感興趣的可以加一下扣群:854393687

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市毅贮,隨后出現(xiàn)的幾起案子办悟,更是在濱河造成了極大的恐慌,老刑警劉巖滩褥,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件病蛉,死亡現(xiàn)場離奇詭異,居然都是意外死亡瑰煎,警方通過查閱死者的電腦和手機铺然,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酒甸,“玉大人魄健,你說我怎么就攤上這事〔迩冢” “怎么了沽瘦?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長农尖。 經(jīng)常有香客問我析恋,道長,這世上最難降的妖魔是什么盛卡? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任助隧,我火速辦了婚禮,結(jié)果婚禮上滑沧,老公的妹妹穿的比我還像新娘并村。我一直安慰自己漏健,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布橘霎。 她就那樣靜靜地躺著蔫浆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姐叁。 梳的紋絲不亂的頭發(fā)上瓦盛,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音外潜,去河邊找鬼原环。 笑死,一個胖子當(dāng)著我的面吹牛处窥,可吹牛的內(nèi)容都是我干的嘱吗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼滔驾,長吁一口氣:“原來是場噩夢啊……” “哼谒麦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哆致,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤绕德,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摊阀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耻蛇,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年胞此,在試婚紗的時候發(fā)現(xiàn)自己被綠了臣咖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡漱牵,死狀恐怖夺蛇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情布疙,我是刑警寧澤蚊惯,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站灵临,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏趴荸。R本人自食惡果不足惜儒溉,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望发钝。 院中可真熱鬧顿涣,春花似錦波闹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蒲障,卻和暖如春歹篓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背揉阎。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工庄撮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毙籽。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓洞斯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坑赡。 傳聞我的和親對象是個殘疾皇子烙如,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 在分布式服務(wù)框架中,一個最基礎(chǔ)的問題就是遠程服務(wù)是怎么通訊的毅否,在Java領(lǐng)域中有很多可實現(xiàn)遠程通訊的技術(shù)厅翔,例如:R...
    wyatt_plus閱讀 828評論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)搀突,斷路器刀闷,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • 你拖著那個黑色旅行箱 來到了我的城市 我的街頭 你請我吃了三個菜一罐冰糖水 我送了你一塊木頭和兩包鮮花種子 沒有花...
    苦桃1閱讀 123評論 0 0
  • 這場大雪之前,好長一段時仰迁,學(xué)校教學(xué)樓一樓二年級教室外邊走廊的墻角處總窩著一條黃色的狗甸昏。 它幾乎天天躺在那兒曬太陽,...
    涅槃_83c4閱讀 517評論 3 3
  • 眾所皆知徐许,Java是當(dāng)前最為流行的編程語言之一施蜜,學(xué)Java的人也開始越來越多了,很多人入門Java時總覺得晦澀難懂...
    java學(xué)習(xí)指南閱讀 257評論 0 0