Dubbo 服務(wù)導(dǎo)出

本篇主要介紹 Dubbo 服務(wù)導(dǎo)出的實現(xiàn)細節(jié)。

定義服務(wù)接口 HelloWorld:

public interface HelloWorld {
    String sayHello();
}

服務(wù)實現(xiàn)類 HelloWorldImpl:

public class HelloWorldImpl implements HelloWorld {
    @Override
    public String sayHello() {

        return "Hello wlm..";
    }
}

服務(wù)導(dǎo)出的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        
        http://dubbo.apache.org/schema/dubbo        
        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
 
    <!-- 提供方應(yīng)用信息石抡,用于計算依賴關(guān)系 -->
    <dubbo:application name="hello-world-app"  />
 
    <!-- 使用 zookeeper 注冊中心暴露服務(wù)地址 -->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>
 
    <!-- 用dubbo協(xié)議在20880端口暴露服務(wù) -->
    <dubbo:protocol name="dubbo" port="20880" />

    <bean id="helloWorldImpl" class="com.wlm.dubbo.service.HelloWorldImpl" />
    <dubbo:service interface="com.wlm.dubbo.service.HelloWorld" ref="helloWorldImpl" version="1.0"/>
    
</beans>

以 Spring 方式啟動服務(wù):

public class DubboStarter {
    public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath*:META-INF/spring/dubbo-start.xml"}, true);
        context.start();
    }
}

解析 bean 屬性

以 Spring 作為容器啟動服務(wù)時初烘,會先解析 bean 的屬性耸别。Spring 的 bean 屬性解析分為默認(rèn)標(biāo)簽和自定義標(biāo)簽兩種徘层,其中自定義標(biāo)簽的解析需要實現(xiàn) NamespaceHandler 接口流纹,Dubbo 的標(biāo)簽 dubbo 即為自定義標(biāo)簽畔师。

Dubbo 定義解析標(biāo)簽的實現(xiàn)類為 DubboNamespaceHandler:


image.png
image.png

這里面定義了 Dubbo 支持的各種標(biāo)簽,比如:application茎芭,registry揖膜,service,reference 等梅桩。

可以看到壹粟,dubbo 的 bean 屬性都通過 DubboBeanDefinitionParser 解析成 BeanDefinition 對象,同時構(gòu)造函數(shù)會傳入最終實例化的 beanClass宿百,比如 service 標(biāo)簽對應(yīng) ServiceBean趁仙,reference 標(biāo)簽對應(yīng) ReferenceBean。具體的實現(xiàn)不是本文的重點垦页,這里就不展開幸撕。

服務(wù)導(dǎo)出入口

根據(jù)前面的說明,服務(wù)提供者相關(guān)的屬性最終會實例化成 ServiceBean 對象外臂,該對象監(jiān)聽了 Spring 的上下文刷新事件 ContextRefreshedEvent,會在 Spring 完成上下文刷新律胀,也就是 bean 完成初始化之后被通知:

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
    if (!isExported() && !isUnexported()) {
        if (logger.isInfoEnabled()) {
            logger.info("The service ready on spring started. service: " + getInterface());
        }
        export();
    }
}

Dubbo 就是在這里開啟服務(wù)導(dǎo)出流程宋光,并且在完成服務(wù)導(dǎo)出之后,發(fā)布服務(wù)導(dǎo)出事件 ServiceBeanExportedEvent:

public void export() {
    super.export();
    // Publish ServiceBeanExportedEvent
    publishExportEvent();
}

具體的導(dǎo)出邏輯由父類 ServiceConfig 實現(xiàn):


image.png
image.png

Dubbo 通過 export 屬性設(shè)置是否導(dǎo)出服務(wù)炭菌,通過 delay 屬性設(shè)置延遲一定時間再導(dǎo)出服務(wù)罪佳。

接下來進入真正的服務(wù)導(dǎo)出流程:


image.png
image.png

分為兩步:加載注冊中心地址,遍歷協(xié)議(ProtocolConfig)列表執(zhí)行服務(wù)導(dǎo)出黑低。

加載注冊中心地址

通過 loadRegistries 方法加載注冊中心地址赘艳,得到一個協(xié)議頭為 registry 的 URL 列表:


image.png
image.png

入?yún)⒈硎臼欠?wù)提供者還是消費者,先遍歷 RegistryConfig 列表克握,將 address 屬性解析成 URL 列表蕾管,格式如下:

zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=wlm
&dubbo=2.0.2&pid=29043&release=2.7.3&timestamp=1578322585876

再將上面的 URL 的協(xié)議頭轉(zhuǎn)換為 registry,原有的協(xié)議頭變?yōu)樾碌?URL 對象的 registry 屬性菩暗,格式如下:

registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=wlm
&dubbo=2.0.2&pid=29043&registry=zookeeper&release=2.7.3&timestamp=1578322585876

服務(wù)導(dǎo)出

通過 doExportUrlsFor1Protocol 執(zhí)行服務(wù)導(dǎo)出掰曾,這里重點關(guān)注 scope=remote (即導(dǎo)出服務(wù)到遠程) 的場景:


image.png
image.png

核心邏輯分為兩步:

  1. 調(diào)用 ProxyFactory#getInvoker:將具體實現(xiàn)類轉(zhuǎn)換為 invoker 對象;
  2. 調(diào)用 Protocol#export:執(zhí)行服務(wù)導(dǎo)出停团,得到 Exporter 對象旷坦。

創(chuàng)建 invoker 對象

Invoker 是 Dubbo 的實體域掏熬,是 Dubbo 的核心模型。

ProxyFactory 即代理工廠類秒梅,是一種動態(tài)代理旗芬,包含兩個操作:

  • getInvoker: 將實現(xiàn)類轉(zhuǎn)換為 invoker 對象;
  • getProxy: 創(chuàng)建遠程服務(wù)的代理捆蜀。

ProxyFactory 支持 SPI 擴展疮丛,默認(rèn)的實現(xiàn)是 JavassistProxyFactory,依賴于 javassist 組件漱办,創(chuàng)建實現(xiàn)類的代理 Wrapper 對象:


image.png
image.png

創(chuàng)建代理類 Wrapper 對象的方式為:先動態(tài)生成代理類的 java 代碼这刷,再編譯代理類,并加載到類加載器中娩井,最后反射創(chuàng)建代理類的實例對象暇屋。

最終生成的代理類結(jié)構(gòu)如下:


image.png
image.png

此處不深究 javassist 的實現(xiàn)細節(jié),展示生成的代理類方法 invokeMethod:


image.png
image.png

JavassistProxyFactory 獲取到 Wrapper 實例對象后洞辣,再封裝成 AbstractProxyInvoker 匿名對象返回咐刨,該對象會將 doInvoke 請求轉(zhuǎn)發(fā)給 Wrapper 對象。

Protocol.export

接下來調(diào)用 Protocol.export 執(zhí)行服務(wù)導(dǎo)出扬霜。

首先通過 Dubbo 自適應(yīng)擴展機制獲取 Protocol 對象:

private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

在 Dubbo SPI 機制中存在一些包裝類(類名以 Wrapper 結(jié)尾定鸟,構(gòu)造函數(shù)參數(shù)為當(dāng)前接口的實現(xiàn)類),而此處 Protocol 的實現(xiàn)類中也存在包裝類著瓶,因此最終得到的是一個 Protocol 鏈:


image.png
image.png

協(xié)議鏈最后一個節(jié)點是 RegistryProtocol联予,是因為協(xié)議頭為 "registry",RegistryProtocol 內(nèi)部還有個 protocol 對象材原,也是通過 Dubbo SPI 機制獲取沸久,也對應(yīng)著一個 Protocol 調(diào)用鏈,前面配置的協(xié)議為 "dubbo":


image.png
image.png

整體的流程圖如下:


image.png
image.png

主要分為以下幾個部分:

  1. 啟動 qos server余蟹;
  2. 構(gòu)建服務(wù)提供者的 Filter 鏈卷胯;
  3. 真正的服務(wù)導(dǎo)出;
  4. 發(fā)布服務(wù)導(dǎo)出事件威酒;
  5. 注冊服務(wù)地址窑睁;
  6. 訂閱

其中 1 在 QosProtocolWrapper 類,2 在 ProtocolFilterWrapper 類葵孤,3 在 DubboProtocol 類担钮,4 在 ProtocolListenerWrapper 類,5佛呻、6 在 RegistryProtocol 類裳朋。

1.啟動 qos server

qos 依賴于 netty,先從 URL 獲取 qos 監(jiān)聽端口信息,再啟動 qos server:


image.png
image.png

啟動 qos server 時鲤嫡,重點關(guān)注兩個操作:注冊解碼器 QosProcessHandler 和監(jiān)聽 qos 端口送挑,其中解碼器負責(zé)把 netty 接收到的字節(jié)流轉(zhuǎn)換成對應(yīng)業(yè)務(wù)所需要的格式:


image.png
image.png

2.構(gòu)建 filter 鏈

構(gòu)建邏輯如下:


image.png
image.png

構(gòu)建 filter 鏈時需要指定三個參數(shù):

  • invoker:當(dāng)前 invoker,形成 filter 鏈的最后一個節(jié)點暖眼;
  • key:指定擴展點名稱惕耕,多個以逗號分隔,從 URL 獲取诫肠,服務(wù)提供者對應(yīng) "service.filter"司澎,消費者對應(yīng) "reference.filter";
  • group:擴展點所屬分組栋豫,提供者和消費者對應(yīng) provider 和 consumer挤安。

構(gòu)建 filter 鏈主要分為以下三個步驟:

  1. 通過 Dubbo SPI 機制獲取 filter 列表;
  2. 將 filter 列表轉(zhuǎn)換為 invoker 調(diào)用鏈丧鸯;
  3. 將 invoker 調(diào)用鏈封裝為支持回調(diào)的 invoker 返回蛤铜;

第1步獲取 filter 鏈?zhǔn)褂昧?@Activate 注解:

public @interface Activate {
    /**
     * 匹配規(guī)則:分組
     */
    String[] group() default {};

    /**
     * 匹配規(guī)則:如果 URL 中出現(xiàn) value 指定的 key,則返回當(dāng)前擴展實現(xiàn)類
     */
    String[] value() default {};

    /**
     * 從小到大排序丛肢,可選
     */
    int order() default 0;
}

Dubbo 獲取的擴展實現(xiàn)類由兩部分組成:

  • @Activate 注解的類:遍歷實現(xiàn)類列表围肥,獲取與指定的 group、value 匹配的實現(xiàn)類蜂怎,并排序穆刻;
  • 入?yún)⒅付ǖ臄U展類名稱,即入?yún)?key杠步,根據(jù)該名稱獲取擴展實現(xiàn)類氢伟,并加到 filter 列表最后。

第2步將調(diào)用 filter 封裝成 invoker 實現(xiàn)類幽歼,上一個創(chuàng)建的 invoker 都是下一個 filter.invoke 入?yún)⒏郑虼?Dubbo 是倒序遍歷 filter 列表,這樣第一個 filter 就是 invoker 調(diào)用鏈的第一個節(jié)點试躏。

第3步將 invoker 調(diào)用鏈封裝為 CallbackRegistrationInvoker 對象,在調(diào)用完 filter 之后设褐,調(diào)用回調(diào)接口:

image.png
image.png

3.真正的服務(wù)導(dǎo)出

在 RegistryProtocol 內(nèi)部颠蕴,調(diào)用了真正的服務(wù)導(dǎo)出邏輯:


image.png
image.png

在 doLocalExport 內(nèi)部,調(diào)用 Protocol.export 導(dǎo)出服務(wù):


image.png
image.png

這里配置的是 "dubbo"助析,即 DubboProtocol犀被,也就是前面介紹的第二個 Protocol 調(diào)用鏈。

整體服務(wù)導(dǎo)出的時序圖如下:


image.png
image.png

上述 Exchanger外冀、Transporter寡键、Server 都支持 SPI 擴展。

概念解釋:
1.Exchanger:信息交換層雪隧,封裝請求響應(yīng)模式西轩,以 Request员舵、Response 為中心,在 Transporter 層基礎(chǔ)之上藕畔,默認(rèn)實現(xiàn)為 HeaderExchanger马僻;

客戶端與服務(wù)端之間的消息發(fā)送模式(即 Message Exchange Pattern)有三種:

  • 數(shù)據(jù)報(Datagram):客戶端發(fā)送消息后,服務(wù)端不會進行回復(fù)注服,比如電視新聞只管發(fā)布消息韭邓;
  • 請求響應(yīng)(Request/Response):客戶端發(fā)送消息后,會等待服務(wù)端的回復(fù)溶弟,比如在街上問路時的一問一答女淑。這也是最常用的消息交換模式;
  • 雙工(Duplex):客戶端和服務(wù)端可以任意的發(fā)送消息辜御,客戶端和服務(wù)端變成通信的兩個端點鸭你,比如兩個人通話時可以同時說話;

Dubbo 的 Exchanger 使用的就是 "請求響應(yīng)" 消息發(fā)送模式我抠,包含了請求和響應(yīng)兩次網(wǎng)絡(luò)傳輸苇本。

2.Transporter:網(wǎng)絡(luò)傳輸層,只有單次網(wǎng)絡(luò)傳輸菜拓,兩端對應(yīng) Client 和 Server瓣窄,以 Message 為中心,默認(rèn)實現(xiàn)為 NettyTransporter纳鼎;

3.Server:即服務(wù)提供者俺夕,與之對應(yīng),Client 為服務(wù)消費者贱鄙,默認(rèn)實現(xiàn)為 NettyServer劝贸。

監(jiān)聽服務(wù)端口的過程中,這些組件都會被創(chuàng)建并初始化。

NettyServer 在初始化時會啟動對服務(wù)端口的監(jiān)聽:


image.png
image.png

這里要注意的是,Dubbo 在 initChannel 時注冊了自定義的編解碼器 NettyCodecAdapter便监,這部分在服務(wù)調(diào)用時再介紹旺入。

4.發(fā)布服務(wù)導(dǎo)出事件

ProtocolListenerWrapper 調(diào)用完 export 后,會返回 ListenerExporterWrapper 包裝類,通過 Dubbo SPI 獲取監(jiān)聽器(由用戶自定義實現(xiàn))ExporterLIstener 列表:


image.png
image.png

并在對象構(gòu)造器內(nèi)調(diào)用 ExporterListener.exported() 發(fā)布服務(wù)導(dǎo)出事件:


image.png
image.png

5.注冊服務(wù)地址

RegistryProtocol 內(nèi)部邏輯如下:


image.png
image.png

先生成注冊中心 URL 信息 registryUrl 和服務(wù)提供方 URL 信息 providerUrl,如下所示:

// registry url
zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=wlm
&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.199.243%3A20880%2Fcom.wlm.dubbo.service
.HelloWorld%3Fanyhost%3Dtrue%26application%3Dwlm%26bean.name%3Dcom.wlm.dubbo.service.
HelloWorld%26bind.ip%3D192.168.199.243%26bind.port%3D20880%26deprecated%3Dfalse%26
dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dcom.wlm.dubbo.service
.HelloWorld%26methods%3DsayHello%26pid%3D40140%26register%3Dtrue%26release%3D2.7.3%26
revision%3D1.0%26service.filter%3DdubboFilter%26side%3Dprovider%26timestamp%3D1578403901317%26
version%3D1.0&pid=40140&release=2.7.3&timestamp=1578403901308

// provider url
dubbo://192.168.199.243:20880/com.wlm.dubbo.service.HelloWorld?anyhost=true
&application=wlm&bean.name=com.wlm.dubbo.service.HelloWorld&bind.ip=192.168.199.243
&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false
&interface=com.wlm.dubbo.service.HelloWorld&methods=sayHello&pid=40140&register=true
&release=2.7.3&revision=1.0&service.filter=dubboFilter&side=provider
&timestamp=1578403901317&version=1.0

provider url 就是 registry url 中的 export 屬性對應(yīng)的值。

注冊服務(wù)地址的邏輯如下:

public void register(URL registryUrl, URL registeredProviderUrl) {
    // 通過注冊中心工廠獲取注冊中心
    Registry registry = registryFactory.getRegistry(registryUrl);
    // 注冊服務(wù)地址
    registry.register(registeredProviderUrl);
}

先從 RegistryFactory 工廠獲取注冊中心 Registry 對象引有,再調(diào)用 Registry.register 將服務(wù)地址注冊到注冊中心。這兩個接口都支持 SPI 擴展倦逐,zookeeper 注冊中心分別對應(yīng)著 ZookeeperRegistryFactory譬正、ZookeeperRegistry。

往 zookeeper 注冊中心注冊服務(wù)地址,即創(chuàng)建目錄節(jié)點:

public void doRegister(URL url) {
    try {
        zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true));
    } catch (Throwable e) {
        throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

最終服務(wù)地址注冊到 zookeeper 路徑:/dubbo/com.wlm.dubbo.service.HelloWorld/providers/曾我,內(nèi)容如下:


image.png
image.png

6.訂閱

服務(wù)訂閱 URL 在服務(wù)提供方 URL 基礎(chǔ)上粉怕,將 protocol 設(shè)置為 "provider",并且添加了 "category" 屬性您单,生成 overrideSubscribeUrl 為:

provider://192.168.199.243:20880/com.wlm.dubbo.service.HelloWorld?anyhost=true
&application=wlm&bean.name=com.wlm.dubbo.service.HelloWorld&bind.ip=192.168.199.243
&bind.port=20880&category=configurators&check=false&deprecated=false&dubbo=2.0.2
&dynamic=true&generic=false&interface=com.wlm.dubbo.service.HelloWorld
&methods=sayHello&pid=39668&register=true&release=2.7.3&revision=1.0
&service.filter=dubboFilter&side=provider&timestamp=1578401531082&version=1.0

接著調(diào)用 ZookeeperRegistry.subscribe 進行訂閱斋荞,入?yún)?overrideSubscribeUrl 和 OverrideListener 對象,OverrideListener 是個監(jiān)聽器虐秦,是 NotifyListener 的子類平酿,訂閱的數(shù)據(jù)發(fā)生變化時會被通知。

ZookeeperRegistry 內(nèi)部根據(jù) interface 是否配置為 * 分為兩種邏輯悦陋,我們重點關(guān)注指定了 interface 的場景:


image.png
image.png

先調(diào)用 toCategoriesPath蜈彼,將 overrideSubscribeUrl 轉(zhuǎn)換為 category 目錄列表,這里只有 configurators:

/dubbo/com.wlm.dubbo.service.HelloWorld/configurators

再遍歷該列表俺驶,執(zhí)行以下邏輯:

  1. 創(chuàng)建監(jiān)聽器 ChildListener幸逆,內(nèi)部調(diào)用入?yún)鬟f的 NotifyListener;
  2. 創(chuàng)建 category 目錄節(jié)點暮现;
  3. 將 ChildListener 注冊到 zookeeper还绘,得到子節(jié)點信息 children;
  4. 調(diào)用 toUrlsWithEmpty 將 overrideSubscribeUrl栖袋、path拍顷、children 信息轉(zhuǎn)換成新的 provider URL。

得到的新 provider URL 格式如下:

empty://192.168.199.243:20880/com.wlm.dubbo.service.HelloWorld?anyhost=true
&application=wlm&bean.name=com.wlm.dubbo.service.HelloWorld&bind.ip=192.168.199.243
&bind.port=20880&category=configurators&check=false&deprecated=false&dubbo=2.0.2
&dynamic=true&generic=false&interface=com.wlm.dubbo.service.HelloWorld&methods=sayHello
&pid=40629&register=true&release=2.7.3&revision=1.0&service.filter=dubboFilter
&side=provider&timestamp=1578406499862&version=1.0

最后主動觸發(fā)一下 notify塘幅。

總結(jié)

本篇文章側(cè)重于 Dubbo 服務(wù)導(dǎo)出的實現(xiàn)細節(jié)昔案,主要包括:服務(wù)導(dǎo)出入口,加載注冊中心地址电媳,創(chuàng)建 invoker 對象踏揣,啟動 qos server,構(gòu)建 filter 鏈匾乓,服務(wù)導(dǎo)出捞稿,發(fā)布服務(wù)導(dǎo)出事件,注冊服務(wù)地址拼缝,訂閱等括享。其中省略了很多細節(jié),比如 Dubbo 的 bean 屬性配置如何解析珍促,并最終得到 URL 等,限于篇幅剩愧,讀者可自行查看猪叙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子穴翩,更是在濱河造成了極大的恐慌犬第,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芒帕,死亡現(xiàn)場離奇詭異歉嗓,居然都是意外死亡,警方通過查閱死者的電腦和手機背蟆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門鉴分,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人带膀,你說我怎么就攤上這事志珍。” “怎么了垛叨?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵伦糯,是天一觀的道長。 經(jīng)常有香客問我嗽元,道長敛纲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任剂癌,我火速辦了婚禮淤翔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘珍手。我一直安慰自己办铡,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布琳要。 她就那樣靜靜地躺著寡具,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稚补。 梳的紋絲不亂的頭發(fā)上童叠,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音课幕,去河邊找鬼厦坛。 笑死,一個胖子當(dāng)著我的面吹牛乍惊,可吹牛的內(nèi)容都是我干的杜秸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼润绎,長吁一口氣:“原來是場噩夢啊……” “哼撬碟!你這毒婦竟也來了诞挨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤呢蛤,失蹤者是張志新(化名)和其女友劉穎惶傻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體其障,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡银室,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了励翼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜈敢。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抚笔,靈堂內(nèi)的尸體忽然破棺而出扶认,到底是詐尸還是另有隱情,我是刑警寧澤殊橙,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布辐宾,位于F島的核電站,受9級特大地震影響膨蛮,放射性物質(zhì)發(fā)生泄漏叠纹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一敞葛、第九天 我趴在偏房一處隱蔽的房頂上張望誉察。 院中可真熱鬧,春花似錦惹谐、人聲如沸持偏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸿秆。三九已至,卻和暖如春怎囚,著一層夾襖步出監(jiān)牢的瞬間卿叽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工恳守, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留考婴,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓催烘,卻偏偏與公主長得像沥阱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子伊群,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

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