聊聊Dubbo - Dubbo可擴(kuò)展機(jī)制實(shí)戰(zhàn)

摘要:在Dubbo的官網(wǎng)上驯击,Dubbo描述自己是一個(gè)高性能的RPC框架。今天我想聊聊Dubbo的另一個(gè)很棒的特性, 就是它的可擴(kuò)展性赠摇。

1. Dubbo的擴(kuò)展機(jī)制

在Dubbo的官網(wǎng)上芍瑞,Dubbo描述自己是一個(gè)高性能的RPC框架。今天我想聊聊Dubbo的另一個(gè)很棒的特性, 就是它的可擴(kuò)展性皮胡。 如同羅馬不是一天建成的痴颊,任何系統(tǒng)都一定是從小系統(tǒng)不斷發(fā)展成為大系統(tǒng)的,想要從一開(kāi)始就把系統(tǒng)設(shè)計(jì)的足夠完善是不可能的屡贺,相反的蠢棱,我們應(yīng)該關(guān)注當(dāng)下的需求锌杀,然后再不斷地對(duì)系統(tǒng)進(jìn)行迭代。在代碼層面泻仙,要求我們適當(dāng)?shù)膶?duì)關(guān)注點(diǎn)進(jìn)行抽象和隔離糕再,在軟件不斷添加功能和特性時(shí),依然能保持良好的結(jié)構(gòu)和可維護(hù)性玉转,同時(shí)允許第三方開(kāi)發(fā)者對(duì)其功能進(jìn)行擴(kuò)展突想。在某些時(shí)候,軟件設(shè)計(jì)者對(duì)擴(kuò)展性的追求甚至超過(guò)了性能究抓。

在談到軟件設(shè)計(jì)時(shí)猾担,可擴(kuò)展性一直被談起,那到底什么才是可擴(kuò)展性刺下,什么樣的框架才算有良好的可擴(kuò)展性呢绑嘹?它必須要做到以下兩點(diǎn):

作為框架的維護(hù)者,在添加一個(gè)新功能時(shí)怠李,只需要添加一些新代碼圾叼,而不用大量的修改現(xiàn)有的代碼,即符合開(kāi)閉原則捺癞。

作為框架的使用者夷蚊,在添加一個(gè)新功能時(shí),不需要去修改框架的源碼髓介,在自己的工程中添加代碼即可惕鼓。

Dubbo很好的做到了上面兩點(diǎn)。這要得益于Dubbo的微內(nèi)核+插件的機(jī)制唐础。接下來(lái)的章節(jié)中我們會(huì)慢慢揭開(kāi)Dubbo擴(kuò)展機(jī)制的神秘面紗箱歧。

2. 可擴(kuò)展的幾種解決方案

通常可擴(kuò)展的實(shí)現(xiàn)有下面幾種:

Factory模式

IoC容器

OSGI容器

Dubbo作為一個(gè)框架一膨,不希望強(qiáng)依賴(lài)其他的IoC容器呀邢,比如Spring,Guice豹绪。OSGI也是一個(gè)很重的實(shí)現(xiàn)价淌,不適合Dubbo。最終Dubbo的實(shí)現(xiàn)參考了Java原生的SPI機(jī)制瞒津,但對(duì)其進(jìn)行了一些擴(kuò)展蝉衣,以滿(mǎn)足Dubbo的需求。

3. Java SPI機(jī)制

既然Dubbo的擴(kuò)展機(jī)制是基于Java原生的SPI機(jī)制巷蚪,那么我們就先來(lái)了解下Java SPI吧病毡。了解了Java的SPI,也就是對(duì)Dubbo的擴(kuò)展機(jī)制有一個(gè)基本的了解屁柏。如果對(duì)Java SPI比較了解的同學(xué)啦膜,可以跳過(guò)有送。

Java SPI(Service Provider Interface)是JDK內(nèi)置的一種動(dòng)態(tài)加載擴(kuò)展點(diǎn)的實(shí)現(xiàn)。在ClassPath的META-INF/services目錄下放置一個(gè)與接口同名的文本文件功戚,文件的內(nèi)容為接口的實(shí)現(xiàn)類(lèi)娶眷,多個(gè)實(shí)現(xiàn)類(lèi)用換行符分隔似嗤。JDK中使用java.util.ServiceLoader來(lái)加載具體的實(shí)現(xiàn)啸臀。 讓我們通過(guò)一個(gè)簡(jiǎn)單的例子,來(lái)看看Java SPI是如何工作的烁落。

定義一個(gè)接口IRepository用于實(shí)現(xiàn)數(shù)據(jù)儲(chǔ)存

interface IRepository { void save(String data); }

提供IRepository的實(shí)現(xiàn) IRepository有兩個(gè)實(shí)現(xiàn)乘粒。MysqlRepository和MongoRepository。

class MysqlRepository implements IRepository { public void save(String data) { System.out.println("Save " + data + " to Mysql"); } }

public class MongoRepository implements IRepository { public void save(String data) { System.out.println("Save " + data + " to Mongo"); } }

添加配置文件 在META-INF/services目錄添加一個(gè)文件伤塌,文件名和接口全名稱(chēng)相同灯萍,所以文件是META-INF/services/com.demo.IRepository。文件內(nèi)容為:

com.demo.MongoRepository com.demo.MysqlRepository

通過(guò)ServiceLoader加載IRepository實(shí)現(xiàn)

ServiceLoader serviceLoader = ServiceLoader.load(IRepository.class); Iterator it = serviceLoader.iterator(); while (it != null && it.hasNext()){ IRepository demoService = it.next(); System.out.println("class:" + demoService.getClass().getName()); demoService.save("tom"); }

在上面的例子中每聪,我們定義了一個(gè)擴(kuò)展點(diǎn)和它的兩個(gè)實(shí)現(xiàn)旦棉。在ClassPath中添加了擴(kuò)展的配置文件,最后使用ServiceLoader來(lái)加載所有的擴(kuò)展點(diǎn)药薯。

4. Dubbo的SPI機(jī)制

Java SPI的使用很簡(jiǎn)單绑洛。也做到了基本的加載擴(kuò)展點(diǎn)的功能。但Java SPI有以下的不足:

需要遍歷所有的實(shí)現(xiàn)童本,并實(shí)例化真屯,然后我們?cè)谘h(huán)中才能找到我們需要的實(shí)現(xiàn)。

配置文件中只是簡(jiǎn)單的列出了所有的擴(kuò)展實(shí)現(xiàn)穷娱,而沒(méi)有給他們命名绑蔫。導(dǎo)致在程序中很難去準(zhǔn)確的引用它們。

擴(kuò)展如果依賴(lài)其他的擴(kuò)展泵额,做不到自動(dòng)注入和裝配

不提供類(lèi)似于Spring的AOP功能

擴(kuò)展很難和其他的框架集成配深,比如擴(kuò)展里面依賴(lài)了一個(gè)Spring bean,原生的Java SPI不支持

所以Java SPI應(yīng)付一些簡(jiǎn)單的場(chǎng)景是可以的嫁盲,但對(duì)于Dubbo篓叶,它的功能還是比較弱的。Dubbo對(duì)原生SPI機(jī)制進(jìn)行了一些擴(kuò)展亡资。接下來(lái)澜共,我們就更深入地了解下Dubbo的SPI機(jī)制。

5. Dubbo擴(kuò)展點(diǎn)機(jī)制基本概念

在深入學(xué)習(xí)Dubbo的擴(kuò)展機(jī)制之前锥腻,我們先明確Dubbo SPI中的一些基本概念嗦董。在接下來(lái)的內(nèi)容中,我們會(huì)多次用到這些術(shù)語(yǔ)瘦黑。

擴(kuò)展點(diǎn)(Extension Point)

是一個(gè)Java的接口京革。

擴(kuò)展(Extension)

擴(kuò)展點(diǎn)的實(shí)現(xiàn)類(lèi)奇唤。

擴(kuò)展實(shí)例(Extension Instance)

擴(kuò)展點(diǎn)實(shí)現(xiàn)類(lèi)的實(shí)例。

擴(kuò)展自適應(yīng)實(shí)例(Extension Adaptive Instance)

第一次接觸這個(gè)概念時(shí)匹摇,可能不太好理解(我第一次也是這樣的...)咬扇。如果稱(chēng)它為擴(kuò)展代理類(lèi),可能更好理解些廊勃。擴(kuò)展的自適應(yīng)實(shí)例其實(shí)就是一個(gè)Extension的代理懈贺,它實(shí)現(xiàn)了擴(kuò)展點(diǎn)接口。在調(diào)用擴(kuò)展點(diǎn)的接口方法時(shí)坡垫,會(huì)根據(jù)實(shí)際的參數(shù)來(lái)決定要使用哪個(gè)擴(kuò)展梭灿。比如一個(gè)IRepository的擴(kuò)展點(diǎn),有一個(gè)save方法冰悠。有兩個(gè)實(shí)現(xiàn)MysqlRepository和MongoRepository堡妒。IRepository的自適應(yīng)實(shí)例在調(diào)用接口方法的時(shí)候,會(huì)根據(jù)save方法中的參數(shù)溉卓,來(lái)決定要調(diào)用哪個(gè)IRepository的實(shí)現(xiàn)皮迟。如果方法參數(shù)中有repository=mysql,那么就調(diào)用MysqlRepository的save方法桑寨。如果repository=mongo伏尼,就調(diào)用MongoRepository的save方法。和面向?qū)ο蟮难舆t綁定很類(lèi)似西疤。為什么Dubbo會(huì)引入擴(kuò)展自適應(yīng)實(shí)例的概念呢烦粒?

Dubbo中的配置有兩種,一種是固定的系統(tǒng)級(jí)別的配置代赁,在Dubbo啟動(dòng)之后就不會(huì)再改了扰她。還有一種是運(yùn)行時(shí)的配置,可能對(duì)于每一次的RPC芭碍,這些配置都不同徒役。比如在xml文件中配置了超時(shí)時(shí)間是10秒鐘,這個(gè)配置在Dubbo啟動(dòng)之后窖壕,就不會(huì)改變了忧勿。但針對(duì)某一次的RPC調(diào)用,可以設(shè)置它的超時(shí)時(shí)間是30秒鐘瞻讽,以覆蓋系統(tǒng)級(jí)別的配置鸳吸。對(duì)于Dubbo而言,每一次的RPC調(diào)用的參數(shù)都是未知的速勇。只有在運(yùn)行時(shí)晌砾,根據(jù)這些參數(shù)才能做出正確的決定。

很多時(shí)候烦磁,我們的類(lèi)都是一個(gè)單例的养匈,比如Spring的bean哼勇,在Spring bean都實(shí)例化時(shí),如果它依賴(lài)某個(gè)擴(kuò)展點(diǎn)呕乎,但是在bean實(shí)例化時(shí)积担,是不知道究竟該使用哪個(gè)具體的擴(kuò)展實(shí)現(xiàn)的。這時(shí)候就需要一個(gè)代理模式了猬仁,它實(shí)現(xiàn)了擴(kuò)展點(diǎn)接口帝璧,方法內(nèi)部可以根據(jù)運(yùn)行時(shí)參數(shù),動(dòng)態(tài)的選擇合適的擴(kuò)展實(shí)現(xiàn)逐虚。而這個(gè)代理就是自適應(yīng)實(shí)例聋溜。 自適應(yīng)擴(kuò)展實(shí)例在Dubbo中的使用非常廣泛谆膳,Dubbo中叭爱,每一個(gè)擴(kuò)展都會(huì)有一個(gè)自適應(yīng)類(lèi),如果我們沒(méi)有提供漱病,Dubbo會(huì)使用字節(jié)碼工具為我們自動(dòng)生成一個(gè)买雾。所以我們基本感覺(jué)不到自適應(yīng)類(lèi)的存在。后面會(huì)有例子說(shuō)明自適應(yīng)類(lèi)是怎么工作的杨帽。

@SPI

@SPI注解作用于擴(kuò)展點(diǎn)的接口上漓穿,表明該接口是一個(gè)擴(kuò)展點(diǎn)∽⒂可以被Dubbo的ExtentionLoader加載晃危。如果沒(méi)有此ExtensionLoader調(diào)用會(huì)異常。

@Adaptive

@Adaptive注解用在擴(kuò)展接口的方法上老客。表示該方法是一個(gè)自適應(yīng)方法僚饭。Dubbo在為擴(kuò)展點(diǎn)生成自適應(yīng)實(shí)例時(shí),如果方法有@Adaptive注解胧砰,會(huì)為該方法生成對(duì)應(yīng)的代碼鳍鸵。方法內(nèi)部會(huì)根據(jù)方法的參數(shù),來(lái)決定使用哪個(gè)擴(kuò)展尉间。

ExtentionLoader

類(lèi)似于Java SPI的ServiceLoader偿乖,負(fù)責(zé)擴(kuò)展的加載和生命周期維護(hù)。

擴(kuò)展別名

和Java SPI不同哲嘲,Dubbo中的擴(kuò)展都有一個(gè)別名贪薪,用于在應(yīng)用中引用它們。比如

random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance

其中的random眠副,roundrobin就是對(duì)應(yīng)擴(kuò)展的別名画切。這樣我們?cè)谂渲梦募惺褂胷andom或roundrobin就可以了。

一些路徑

和Java SPI從/META-INF/services目錄加載擴(kuò)展配置類(lèi)似侦啸,Dubbo也會(huì)從以下路徑去加載擴(kuò)展配置文件:

META-INF/dubbo/internal

META-INF/dubbo

META-INF/services

6. Dubbo的LoadBalance擴(kuò)展點(diǎn)解讀

在了解了Dubbo的一些基本概念后槽唾,讓我們一起來(lái)看一個(gè)Dubbo中實(shí)際的擴(kuò)展點(diǎn)丧枪,對(duì)這些概念有一個(gè)更直觀的認(rèn)識(shí)。

我們選擇的是Dubbo中的LoadBalance擴(kuò)展點(diǎn)庞萍。Dubbo中的一個(gè)服務(wù)拧烦,通常有多個(gè)Provider,consumer調(diào)用服務(wù)時(shí)钝计,需要在多個(gè)Provider中選擇一個(gè)恋博。這就是一個(gè)LoadBalance。我們一起來(lái)看看在Dubbo中私恬,LoadBalance是如何成為一個(gè)擴(kuò)展點(diǎn)的债沮。

LoadBalance接口

@SPI(RandomLoadBalance.NAME) public interface LoadBalance { @Adaptive("loadbalance") Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException; }

LoadBalance接口只有一個(gè)select方法。select方法從多個(gè)invoker中選擇其中一個(gè)本鸣。上面代碼中和Dubbo SPI相關(guān)的元素有:

@SPI(RandomLoadBalance.NAME) @SPI作用于LoadBalance接口疫衩,表示接口LoadBalance是一個(gè)擴(kuò)展點(diǎn)。如果沒(méi)有@SPI注解荣德,試圖去加載擴(kuò)展時(shí)闷煤,會(huì)拋出異常。@SPI注解有一個(gè)參數(shù)涮瞻,該參數(shù)表示該擴(kuò)展點(diǎn)的默認(rèn)實(shí)現(xiàn)的別名鲤拿。如果沒(méi)有顯示的指定擴(kuò)展,就使用默認(rèn)實(shí)現(xiàn)署咽。RandomLoadBalance.NAME是一個(gè)常量近顷,值是"random",是一個(gè)隨機(jī)負(fù)載均衡的實(shí)現(xiàn)宁否。 random的定義在配置文件META-INF/dubbo/internal/com.alibaba.dubbo.rpc.cluster.LoadBalance中:

random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance

可以看到文件中定義了4個(gè)LoadBalance的擴(kuò)展實(shí)現(xiàn)窒升。由于負(fù)載均衡的實(shí)現(xiàn)不是本次的內(nèi)容,這里就不過(guò)多說(shuō)明家淤。只用知道Dubbo提供了4種負(fù)載均衡的實(shí)現(xiàn)异剥,我們可以通過(guò)xml文件,properties文件絮重,JVM參數(shù)顯式的指定一個(gè)實(shí)現(xiàn)冤寿。如果沒(méi)有,默認(rèn)使用隨機(jī)青伤。

@Adaptive("loadbalance") @Adaptive注解修飾select方法督怜,表明方法select方法是一個(gè)可自適應(yīng)的方法。Dubbo會(huì)自動(dòng)生成該方法對(duì)應(yīng)的代碼狠角。當(dāng)調(diào)用select方法時(shí)号杠,會(huì)根據(jù)具體的方法參數(shù)來(lái)決定調(diào)用哪個(gè)擴(kuò)展實(shí)現(xiàn)的select方法。@Adaptive注解的參數(shù)loadbalance表示方法參數(shù)中的loadbalance的值作為實(shí)際要調(diào)用的擴(kuò)展實(shí)例。 但奇怪的是姨蟋,我們發(fā)現(xiàn)select的方法中并沒(méi)有l(wèi)oadbalance參數(shù)屉凯,那怎么獲取loadbalance的值呢?select方法中還有一個(gè)URL類(lèi)型的參數(shù)眼溶,Dubbo就是從URL中獲取loadbalance的值的悠砚。這里涉及到Dubbo的URL總線模式,簡(jiǎn)單說(shuō)堂飞,URL中包含了RPC調(diào)用中的所有參數(shù)灌旧。URL類(lèi)中有一個(gè)Map parameters字段,parameters中就包含了loadbalance绰筛。

獲取LoadBalance擴(kuò)展

Dubbo中獲取LoadBalance的代碼如下:

LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName);

使用ExtensionLoader.getExtensionLoader(LoadBalance.class)方法獲取一個(gè)ExtensionLoader的實(shí)例枢泰,然后調(diào)用getExtension,傳入一個(gè)擴(kuò)展的別名來(lái)獲取對(duì)應(yīng)的擴(kuò)展實(shí)例铝噩。

7. 自定義一個(gè)LoadBalance擴(kuò)展

本節(jié)中衡蚂,我們通過(guò)一個(gè)簡(jiǎn)單的例子,來(lái)自己實(shí)現(xiàn)一個(gè)LoadBalance薄榛,并把它集成到Dubbo中讳窟。我會(huì)列出一些關(guān)鍵的步驟和代碼,也可以從這個(gè)地址(https://github.com/vangoleo/dubbo-spi-demo)下載完整的demo敞恋。

實(shí)現(xiàn)LoadBalance接口

首先,編寫(xiě)一個(gè)自己實(shí)現(xiàn)的LoadBalance谋右,因?yàn)槭菫榱搜菔綝ubbo的擴(kuò)展機(jī)制硬猫,而不是LoadBalance的實(shí)現(xiàn),所以這里L(fēng)oadBalance的實(shí)現(xiàn)非常簡(jiǎn)單改执,選擇第一個(gè)invoker啸蜜,并在控制臺(tái)輸出一條日志。

package com.dubbo.spi.demo.consumer; public class DemoLoadBalance implements LoadBalance { @Override public Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException { System.out.println("DemoLoadBalance: Select the first invoker..."); return invokers.get(0); } }

添加擴(kuò)展配置文件

添加文件:META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance辈挂。文件內(nèi)容如下:

demo=com.dubbo.spi.demo.consumer.DemoLoadBalance

配置使用自定義LoadBalance

通過(guò)上面的兩步衬横,已經(jīng)添加了一個(gè)名字為demo的LoadBalance實(shí)現(xiàn),并在配置文件中進(jìn)行了相應(yīng)的配置终蒂。接下來(lái)蜂林,需要顯式的告訴Dubbo使用demo的負(fù)載均衡實(shí)現(xiàn)。如果是通過(guò)spring的方式使用Dubbo拇泣,可以在xml文件中進(jìn)行設(shè)置噪叙。

在consumer端的dubbo:reference中配置

啟動(dòng)Dubbo

啟動(dòng)Dubbo,調(diào)用一次IHelloService霉翔,可以看到控制臺(tái)會(huì)輸出一條DemoLoadBalance: Select the first invoker...日志睁蕾。說(shuō)明Dubbo的確是使用了我們自定義的LoadBalance。

總結(jié)

到此,我們從Java SPI開(kāi)始子眶,了解了Dubbo SPI 的基本概念瀑凝,并結(jié)合了Dubbo中的LoadBalance加深了理解。最后臭杰,我們還實(shí)踐了一下猜丹,創(chuàng)建了一個(gè)自定義LoadBalance,并集成到Dubbo中硅卢。相信通過(guò)這里理論和實(shí)踐的結(jié)合射窒,大家對(duì)Dubbo的可擴(kuò)展有更深入的理解。

總結(jié)一下将塑,Dubbo SPI有以下的特點(diǎn):

? 對(duì)Dubbo進(jìn)行擴(kuò)展脉顿,不需要改動(dòng)Dubbo的源碼

? 自定義的Dubbo的擴(kuò)展點(diǎn)實(shí)現(xiàn),是一個(gè)普通的Java類(lèi)点寥,Dubbo沒(méi)有引入任何Dubbo特有的元素艾疟,對(duì)代碼侵入性幾乎為零。

? 將擴(kuò)展注冊(cè)到Dubbo中敢辩,只需要在ClassPath中添加配置文件蔽莱。使用簡(jiǎn)單。而且不會(huì)對(duì)現(xiàn)有代碼造成影響戚长。符合開(kāi)閉原則盗冷。

? Dubbo的擴(kuò)展機(jī)制支持IoC,AoP等高級(jí)功能

? Dubbo的擴(kuò)展機(jī)制能很好的支持第三方IoC容器,默認(rèn)支持Spring Bean同廉,可自己擴(kuò)展來(lái)支持其他容器仪糖,比如Google的Guice。

? 切換擴(kuò)展點(diǎn)的實(shí)現(xiàn)迫肖,只需要在配置文件中修改具體的實(shí)現(xiàn)锅劝,不需要改代碼。使用方便蟆湖。

原文鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末故爵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子隅津,更是在濱河造成了極大的恐慌诬垂,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饥瓷,死亡現(xiàn)場(chǎng)離奇詭異剥纷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)呢铆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)晦鞋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事悠垛∠叨ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵确买,是天一觀的道長(zhǎng)斤讥。 經(jīng)常有香客問(wèn)我,道長(zhǎng)湾趾,這世上最難降的妖魔是什么芭商? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮搀缠,結(jié)果婚禮上铛楣,老公的妹妹穿的比我還像新娘。我一直安慰自己艺普,他們只是感情好簸州,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著歧譬,像睡著了一般岸浑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瑰步,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天矢洲,我揣著相機(jī)與錄音,去河邊找鬼面氓。 笑死兵钮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舌界。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼泰演,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼呻拌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起睦焕,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤藐握,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后垃喊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體猾普,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年本谜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了初家。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖溜在,靈堂內(nèi)的尸體忽然破棺而出陌知,到底是詐尸還是另有隱情,我是刑警寧澤掖肋,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布仆葡,位于F島的核電站,受9級(jí)特大地震影響志笼,放射性物質(zhì)發(fā)生泄漏沿盅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一纫溃、第九天 我趴在偏房一處隱蔽的房頂上張望腰涧。 院中可真熱鬧,春花似錦皇耗、人聲如沸南窗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)万伤。三九已至,卻和暖如春呜袁,著一層夾襖步出監(jiān)牢的瞬間敌买,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工阶界, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留虹钮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓膘融,卻偏偏與公主長(zhǎng)得像芙粱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子氧映,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • 0 前言 站在一個(gè)框架作者的角度來(lái)說(shuō)春畔,定義一個(gè)接口,自己默認(rèn)給出幾個(gè)接口的實(shí)現(xiàn)類(lèi)岛都,同時(shí) 允許框架的使用者也能夠自定...
    七寸知架構(gòu)閱讀 16,249評(píng)論 3 67
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理律姨,服務(wù)發(fā)現(xiàn),斷路器臼疫,智...
    卡卡羅2017閱讀 134,661評(píng)論 18 139
  • 前面我們了解過(guò)了Java的SPI擴(kuò)展機(jī)制择份,對(duì)于Java擴(kuò)展機(jī)制的原理以及優(yōu)缺點(diǎn)也有了大概的了解,這里繼續(xù)深入一下D...
    加大裝益達(dá)閱讀 5,062評(píng)論 2 20
  • 01 睡到半夜烫堤,杜青突然被孩子不斷的翻滾弄醒了荣赶。 三歲多的小孩在床上左右翻滾凤价,發(fā)出沉重的呼吸聲。杜青伸手一摸額頭讯壶,...
    左生生閱讀 1,276評(píng)論 18 20
  • 文/慢蝸牛 臘月二十七 這是心靈自由寫(xiě)作的第十六篇作業(yè)料仗。 此時(shí),我已經(jīng)坐上回家的火車(chē)了伏蚊。就在昨天下午立轧,我剛結(jié)束手中...
    慢蝸牛兒閱讀 230評(píng)論 0 0