spring源碼案例分析之健康檢查

????????今天給大家?guī)淼姆治霭咐莝pringboot集成的程序健康檢測案例氧腰,首先是基于springboot1.5.13版本诅福,其次主要分析的包如下圖所示泛范。

主要類包

????????之所以要分析這塊內(nèi)容,其實(shí)還是由于工作上導(dǎo)致的谍夭,前段時間黑滴,運(yùn)維想要讓我們在程序種加入一個可以訪問程序狀態(tài)的路徑,以便于運(yùn)維檢測程序慧库,然后springboot也自帶了這個功能,所以我就直接使用了馋嗜,但是使用的過程種齐板,發(fā)現(xiàn)了一個問題,如下圖所示。

????????顯示我的db的狀態(tài)為unknown甘磨,這我就瞬間來精神了橡羞,憑啥我得db就是unknown狀態(tài),難道不配顯示信息嗎济舆?當(dāng)然這是玩笑之話卿泽,為啥顯示未知狀態(tài),肯定還是由程序判斷的結(jié)果滋觉,至于原因签夭,我們接下來具體分析這一塊內(nèi)容,也會順帶分析到整個健康檢測的一些核心機(jī)制功能實(shí)現(xiàn)點(diǎn)椎侠。

? ? ? ? 至于如何引入spring健康檢查第租,在boot的情況下,下面?zhèn)z張圖估計大家都應(yīng)該明白了我纪。

主要引入的jar包
yml文件需要配置的點(diǎn)

? ? ? ? 懷著好奇心態(tài)的我慎宾,對引入jar沒啥興趣,但是我有點(diǎn)對這個配置感興趣浅悉,我懷著試試的心態(tài)趟据,直接把這個配置給刪除了,然后重新訪問了/health路徑术健,如下圖所示汹碱。

? ? ? ? 好家伙,還有這么一手苛坚,配置不配置依舊還會顯示信息比被,但是顯示的信息不一樣,于是我們帶著疑問進(jìn)行分析去了泼舱。

? ? ? ? 首先我們分析下這個配置究竟是干嘛的等缀,根據(jù)spring自帶的配置提示,如下圖所示

org.springframework.boot.actuate.autoconfigure.ManagementServerProperties

我們找到了配置的類在這里娇昙,所有在yml中配置的信息都會注入到這個類中尺迂。關(guān)于配置信息,我們先簡單分析這到冒掌,后續(xù)會有關(guān)聯(lián)點(diǎn)噪裕。

????????接下來我們分析/health這個路徑,大家都知道股毫,既然我能通過http訪問這個/health膳音,說明他在spring容器中肯定存在一個控制器,但是我們并沒有自己去寫這個控制器铃诬,由此猜測可能是spring自己注冊的祭陷,這里就有點(diǎn)小麻煩了苍凛,如果我們自己寫的話找起來還比較好找,因?yàn)橹苯邮褂胕dea搜索或者包都瀏覽一遍兵志,但是spring自己注冊的話醇蝴,就不可控了,鬼知道他是怎么注冊進(jìn)去的想罕,我們先試著使用idea全局搜索試一下:

我們發(fā)現(xiàn)了這個使用點(diǎn)悠栓,但是經(jīng)過排查,發(fā)現(xiàn)并不是我們要找的按价。貌似這樣我們又陷入了黑暗惭适,感覺前途一片黑暗,spring源碼分析之路宣告封閉俘枫,總不能把spring所有類都看一遍找找在哪注冊了這個/health腥沽,估計看完頭發(fā)都掉完了。各位莫著急鸠蚪,我這里教大家倆招今阳,保證手到擒來:

第一種方式:

? ? ? ? 觀看spring啟動日志,

會有這么一行數(shù)據(jù)

2021-01-15 09:59:29 [main] [org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry:543] - Mapped "{[/health || /health.json],methods=[GET],produces=[application/vnd.spring-boot.actuator.v1+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,java.security.Principal)

到這里估計大家都看明白了茅信,spring啟動大多數(shù)情況下會默認(rèn)輸出所有控制器的映射信息盾舌,包括對應(yīng)的handler,上面的信息告訴我們蘸鲸,這個/health對應(yīng)的控制器為HealthMvcEndpoint妖谴,我們一會再去分析這個類。接下來看第二種方式酌摇。

第二種方式:

? ? ? ? debug源碼膝舅,這個需要對springmvc相關(guān)源碼比較熟悉的人適用,大家都知道窑多,我們spring有一個核心servlet就是dispatcherservlet仍稀,所有的映射控制器處理,都要經(jīng)過他轉(zhuǎn)發(fā)埂息,因此我們直接去到這個類技潘。

在第940行打上斷點(diǎn),然后使用postman或者瀏覽器發(fā)起請求千康,就會自動跳轉(zhuǎn)到這個斷點(diǎn)上享幽,至于如何定位到doDispatcher以及這個mappedHandler,詳細(xì)過程需要結(jié)合springmvc部份的源碼以及梳理拾弃,這里就暫不深究了值桩,有興趣的小伙伴們可以私信或者留言告訴我,我抽時間可以安排一下豪椿,你懂得奔坟!

? ? ? ? 好了斯入,倆種方式大致上已經(jīng)告訴小伙伴們了,這里再說一點(diǎn)蛀蜜,貌似還有一種方式可以使用接口請求輸出所有映射的詳細(xì)信息,這里也不深究了增蹭,這倆種方式不僅僅限于本篇文章的用途滴某,以后你們?nèi)绻蚕肴ふ夷硞€映射或者控制器,都可以使用這倆種方式滋迈。還是比較實(shí)用的霎奢。

? ? ? ? 接下來,我們重點(diǎn)去分析這個HealthMvcEndpoint類饼灿。

我們可以看到invoke方法上使用的是AcutorGetMapping幕侠,本質(zhì)上還是屬于RequestMapping的一種,因此這個invoke方法肯定是我們需要過一遍的碍彭,首先我們先簡單分析?

!getDelegate().isEnabled())

private static final String ENDPOINTS_ENABLED_PROPERTY = "endpoints.enabled";

我們并沒有配置上面這個變量晤硕,他也沒有默認(rèn)的屬性值在容器中,因此這個值肯定不存在的庇忌,所以在第73行判斷條件為false舞箍,默認(rèn)返回return true。所以不會走if里面的語句皆疹。

進(jìn)入getHealth方法中疏橄,發(fā)現(xiàn)會調(diào)用getCurrentHealth,在這個方法中略就,sprng做了一個緩存機(jī)制捎迫,把得到的cachedHealth緩存了起來,并且有一個時間過期機(jī)制表牢。第一次調(diào)用的時候這個cachedHealth肯定是null窄绒,因此我們需要分析getDelegate().invoke()方法,getDeleagte()方法屬于超類中的方法初茶,會返回一個泛型的delegate對象颗祝,我們簡單看下超類的結(jié)構(gòu)

有很多子類都實(shí)現(xiàn)了這個超類,分別提供不同的功能恼布,我們這次研究的HealthMvcEndpoint就屬于其中之一螺戳,并且這個超類中還有一個泛型變量delegate,這個也是在類實(shí)例化階段需要填充的折汞,這個我們稍后在分析倔幼,這個泛型變量具體類型基于子類的實(shí)現(xiàn)方式,我們看到子類HealthMvcEndpoint中明確了泛型為HealthEndpoint類型爽待,接下來接續(xù)分析delegate.invoke()方法

可以看到healthIndicator是在構(gòu)造函數(shù)中進(jìn)行初始化的损同,老樣子翩腐,繼續(xù)走主流程,稍后在分析這塊如何初始化的膏燃,這個類名是CompositeHealthIndicators茂卦,看類名就是綜合健康檢查的意思,一目了然组哩。

繼續(xù)分析health()方法

我們可以看到這個indicators是由一個map組成等龙,value存的是所有spring集成的第三方中間件的健康檢查的控件類,有redis伶贰,db蛛砰,mail,config等等黍衙,然后for循環(huán)這個indicators泥畅,在healths中會放入各個中間件的一些健康信息,最后調(diào)用healthAggregator進(jìn)行聚合處理琅翻。我們先簡單看一個redis的健康檢查控件

org.springframework.boot.actuate.health.RedisHealthIndicator

我們進(jìn)入到這個類中

這個類比較簡單位仁,就一個核心方法doHealthCheck,了解spring源碼的人都應(yīng)該清楚方椎,像這種方法名一看就是被調(diào)用的障癌,而且絕大多數(shù)是在本類,但我們這個本類沒有其他方法辩尊,而且這個方法是重寫的泻蚊,因此我們?nèi)コ愔锌纯唇Y(jié)構(gòu)骚亿。

我們看到了超類中定義了一個抽象方法,并且在health()方法中進(jìn)行調(diào)用,這個health方法就是上面CompositeHealthIndicators類中進(jìn)行重寫的health方法中進(jìn)行for循環(huán)調(diào)用的地方误算。當(dāng)調(diào)用到RedisHealthIndicator的health方法的時候嚎花,會默認(rèn)調(diào)用超類的health方法撩嚼,然后通過重寫的方法調(diào)用到子類的doHealthCheck捆憎,這是典型的模板方法設(shè)計模式。其實(shí)設(shè)計模式也挺實(shí)用的迟隅,雖然我也不是很清楚每種場景的設(shè)計模式但骨。

我們重點(diǎn)分析doHealthCheck,首先方法通過redisConnectionFactory獲取一個redisconnection智袭,如果獲取到了則說明redis狀態(tài)一且正常奔缠,且可以獲取redis一些版本以及其他信息,這里大家看到connection做了類型判斷吼野,判斷是集群模式還是單機(jī)模式校哎,不同的類型走不同的處理邏輯,我們這邊不研究這個了。這里需要注意的一個點(diǎn)是闷哆,我們并沒看到down的處理邏輯腰奋,而且我們應(yīng)該了解如果connection獲取不到,肯定會報socket連接異常抱怔,但是這里異常雖然try了劣坊,并沒有catch,因此異城簦肯定會往上層代碼拋出讼稚,我們?nèi)タ闯惖奶幚?/p>

try {

doHealthCheck(builder);

}

catch (Exception ex) {

this.logger.warn("Health check failed", ex);

builder.down(ex);

}

一且都很清晰明了了,這里不但會打印日志绕沈,還會將這個中間件標(biāo)記為down狀態(tài)。

redis的其實(shí)并沒有什么難度帮寻,當(dāng)我準(zhǔn)備分析db的時候乍狐,也覺得大致一樣,但是真正分析的時候還是有點(diǎn)不同的固逗,還是比較有趣的浅蚪,我們帶著db為啥是unknown的狀態(tài)的疑問,接下來我們重點(diǎn)分析db的健康檢查原理烫罩。

分析前我們先看上面一張圖惜傲,我們會發(fā)現(xiàn)這個linkedhashmap中的db的value明顯和別的不一樣,上面我們已經(jīng)分析過了redis的健康檢查控件就是RedisHealthIndicator贝攒,但是這個db的卻是CompositeHealthIndicator盗誊,再看下面這張圖

org.springframework.boot.actuate.health.DataSourceHealthIndicator

明明是有db的專屬控件的,為什么這里health方法中卻不是呢隘弊,通過查看DataSourceHealthIndicator在哪被初始化哈踱,如下圖所示進(jìn)行研究

我們看上面這個很重要的類,org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration

顧名思義梨熙,這個類是基本所有spring集成中間件健康檢查的自動裝配類开镣。這時候有人會問我,你怎么找到這個類的呢咽扇,總不能一個個去看吧邪财,其實(shí)很簡單,我們把鼠標(biāo)放在DataSourceHealthIndicator類名上质欲,使用idea的find usages(alt+f7)就可以知道這個類在哪里被調(diào)用树埠、使用、初始化等等嘶伟。

我們還是繼續(xù)分析這個HealthIndicatorAutoConfiguration弥奸,它由眾多靜態(tài)內(nèi)部類組成,基本每個靜態(tài)內(nèi)部類都是一個中間件的健康檢查裝配類奋早,我們看上面關(guān)于db的裝配類盛霎,在重點(diǎn)分析第222行@bean注解的方法之前赠橙,我們先看下第193行這個db靜態(tài)內(nèi)部類的構(gòu)造方法,因?yàn)檫@個有個屬性的初始化跟后面的分析有關(guān)愤炸,構(gòu)造方法中期揪,它初始化了倆個屬性如下:

this.dataSources = filterDataSources(dataSources.getIfAvailable());

this.metadataProviders = metadataProviders.getIfAvailable();

我們主要看第一個,dataSources的初始化规个,調(diào)用了filterDataSources方法凤薛,傳參是

dataSources.getIfAvailable(),類型是ObjectProvider<Map<String, DataSource>> dataSources

關(guān)于這種ObjectProvider類型的參數(shù)诞仓,其實(shí)是spring獨(dú)特的一個注入方式缤苫,我們這里不深究了,以后有機(jī)會在講墅拭,這個變量的主要作用就是spring容器初始化這個構(gòu)造函數(shù)的時候活玲,會把容器中所有dataSource的對象注入到這個容器中,key就是dataSource的beanName谍婉,value就是dataSource舒憾。

因此我們看filterDataSources方法,正常程序中一般都會有dataSource的對象穗熬,所以第202行不會成立镀迂,繼續(xù)往下看,第206唤蔗,207行判斷這個map的value是否是AbstractRoutingDataSource的子類探遵,關(guān)于

org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource

有的小伙伴可能不太了解,這個是spring多數(shù)據(jù)源的一個超類妓柜。如果你的項目中别凤,需要使用多數(shù)據(jù)源,那么這個類你必然會用到领虹,而我這個程序中也正好是使用了多數(shù)據(jù)源规哪,因此當(dāng)程序走到這一步的時候,不會走if分支塌衰,直接返回一個空的數(shù)據(jù)源map給類的私有屬性诉稍。

說完了上面類的構(gòu)造方法,我們繼續(xù)看被@bean注解的dbHealthIndicator方法最疆,接觸過springboot的都知道杯巨,所有含有@bean的方法,只要被spring容器掃描到努酸,那么在容器初始化階段的時候服爷,就會去解析這個bean注入到容器中,這個方法會調(diào)用createHealthIndicator方法,這個方法是來自于超類

這個類一共就倆個方法仍源,并且是重載的心褐,一個接受map參數(shù)返回HealthIndicator,一個接受泛型變量返回泛型對象笼踩。

第二個方法比較復(fù)雜逗爹,因?yàn)樵赿bHealthIndicator中調(diào)用的createHealthIndicator傳的參數(shù)是一個map,所以我們這里只需看第一個嚎于,首先是if條件掘而,上文我們也知道了,多數(shù)據(jù)源的dataSource是不會放入到map中的于购,因此在這里不會走if袍睡,直接new一個CompositeHealthIndicator,參數(shù)是HealthAggregator肋僧,且下面的for循環(huán)也沒有任何意義斑胜,直接會跳過,返回這個composite色瘩,這樣我們db的健康檢查控件就初始化完畢了,不太像我們之前redis分析的那樣逸寓,簡單明了居兆,這里貌似彎彎繞繞比較多,對于這個CompositeHealthIndicator竹伸,我們貌似有點(diǎn)眼熟泥栖,上文貌似是在HealthEndpoint中有這個,為啥db也是這個呢

我們再來看下這個類勋篓,其實(shí)這里spring相當(dāng)于刷了一個小聰明吧享,它復(fù)用了這個類,在無法正常初始化中間件的控件的時候譬嚣,就像上面db的datasource為空的時候钢颂,他就默認(rèn)初始化一個CompositeHealthIndicator,我們看這個health方法拜银,和之前分析這個health不同殊鞭,我們這里indicators為空,所以不會走for循環(huán)尼桶,所以我們看下第70行方法操灿,傳入的是一個空的healths,

這里aggregate方法里面處理了這個healths變量泵督,37行因?yàn)榭盏膍ap不會走趾盐,所以他會調(diào)用抽象方法,aggregateStatus方法,入?yún)⑹且粋€空的集合

這個抽象類默認(rèn)就一個子類救鲤,這個子類重寫了aggregateStatus久窟,首先因?yàn)槿雲(yún)⑹强占希缘谝粋€for循環(huán)不會走蜒简,到if語句的時候瘸羡,因?yàn)檫@個方法內(nèi)部變量依舊是空集合,所以條件成立搓茬,返回狀態(tài)為unknown狀態(tài)犹赖。所以這就解釋了為啥我程序中db狀態(tài)為啥是unknown狀態(tài)。到此為止我們梳理下整個的調(diào)用鏈路:

首先是HealthMvcEndpoint調(diào)用了invoke方法卷仑,而invoke最終調(diào)用了HealthEndpoint中的invoke方法峻村,然后在invoke方法中調(diào)用healthIndicator變量進(jìn)行for循環(huán)所有中間件健康檢查控件類的health方法,如果能正常初始化的控件就會正常顯示狀態(tài)up或者down(如redis)锡凝,如果不能正常初始化的則會默認(rèn)賦值一個控件粘昨,如多數(shù)據(jù)源情況下的db控件,則絕大多數(shù)都會返回unknown狀態(tài)窜锯。

文章到這里张肾,開始的問題已經(jīng)分析出了因果,我們在分析問題的時候還留下了幾個其他疑問锚扎,分別如下:

1吞瞪、ManagementServerProperties類的配置究竟有何作用?(為什么配置了就會顯示更多信息驾孔,不配就只顯示一個狀態(tài))

2芍秆、HealthMvcEndpoint類中delegate是如何初始化的?

3翠勉、HealthEndpoint中的healthIndicator是如何初始化的妖啥?

我們一個個來分析,首先第一個問題:

我們看到Health類中包含了status以及details对碌,status就是狀態(tài)荆虱,而details是各個中間件的詳細(xì)信息,就像一開始文章所示的請求返回信息一樣朽们,包含redis的版本信息克伊,磁盤信息等。上面getHealth方法中有個exposeHealthDetails方法华坦,如果這個方法返回true則是返回詳細(xì)信息愿吹,如果false,則看下面的構(gòu)造只返回status惜姐。因此我們需要看下這個方法犁跪,

這個方法首先先判斷this.secure,如果是false直接返回true椿息,如果是true則走下面。/health要想返回詳細(xì)信息這里一定得是false坷衍,我們看下這個secure是在那里初始化得寝优。

首先是在構(gòu)造函數(shù)中被初始化的,我們接下來看構(gòu)造函數(shù)被誰調(diào)用

這里注意看構(gòu)造函數(shù)的參數(shù)其中是由一個managementServerProperties.getSecurity().isEnabled()傳入的枫耳,我們點(diǎn)進(jìn)去看下

原來我們在yml中配置的屬性乏矾,最終都會注入到這個類中,并且在HealthMvcEndpoint類初始化的時候一并傳入過去迁杨,然后處理相關(guān)邏輯的時候會使用到這些屬性钻心。這就解釋了我們第一個問題。

第二個問題铅协,HealthMvcEndpoint類中delegate是如何初始化的捷沸?

我們看到healthMvcEndpoint構(gòu)造函數(shù)中傳入這個delegate,經(jīng)過排查狐史,發(fā)現(xiàn)在@bean方法中進(jìn)行初始化的痒给,

再通過上面這張圖我們很清晰就能明白,這個delegate本身也會作為一個bean放入到容器中骏全,然后作為構(gòu)造參數(shù)注入到別的類中進(jìn)行調(diào)用苍柏。因此第二個問題就分析完了。

第三個問題姜贡,HealthEndpoint中的healthIndicator是如何初始化的试吁?

我們看上面圖示,第56行new了一個默認(rèn)的CompositeHealthIndicator鲁豪,然后經(jīng)過一個for循環(huán)處理潘悼,填充了一下healthIndicator的內(nèi)部變量indicators律秃,因此我們的重點(diǎn)是這個構(gòu)造函數(shù)的healthIndicators變量爬橡。

可以看到這個構(gòu)造函數(shù)參數(shù)是由this的一個變量傳遞的,經(jīng)過上面的分析棒动,這里不是空糙申,所以肯定是有值的,

這個this.healthIndicators是由ObjectProvider類調(diào)用getIfAvailable方法得到來的船惨,這個方法我們上面分析過柜裸,其實(shí)這是spring常用的一種注入方式,結(jié)果就是能夠到所有的HealIndicator的bean的map對象粱锐,key為beanname疙挺,value為bean,這里也不深究了怜浅,如果有想了解這塊知識的可以私信留言告訴我铐然,我到時候整理講解一下蔬崩。

因此關(guān)于前面遺留的三個問題我也間接的回答完了,你們也可以自己去嘗試分析一下搀暑,看一下是否如上所說沥阳。這一期的案例分析就說到這里了。

這篇文章還是讓我花了不少時間去書寫和思考的自点,如果有喜歡的小伙伴一定要點(diǎn)擊收藏點(diǎn)贊哦桐罕,你們的贊揚(yáng)是我繼續(xù)的動力,哈哈桂敛,客套話了功炮。想關(guān)于這篇文章討論的可以在下方留言,我看到了隨時會回復(fù)的埠啃。

寫在文后:

關(guān)于下篇文章死宣,我準(zhǔn)備寫一篇關(guān)于springboot初始化相關(guān)的文章,主要還是針對于問題而去分析的碴开,我這里可以先拋出問題毅该,留給各位去思考:

如果spring中有一個bean,我們自己也去定義了潦牛,為什么springboot會默認(rèn)先初始化我們的類眶掌?

關(guān)于這個問題的討論也可放在下方去留言。巴碗。朴爬。。橡淆。召噩。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載逸爵,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者具滴。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市师倔,隨后出現(xiàn)的幾起案子构韵,更是在濱河造成了極大的恐慌,老刑警劉巖趋艘,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疲恢,死亡現(xiàn)場離奇詭異,居然都是意外死亡瓷胧,警方通過查閱死者的電腦和手機(jī)显拳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搓萧,“玉大人杂数,你說我怎么就攤上這事遇八。” “怎么了耍休?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵刃永,是天一觀的道長。 經(jīng)常有香客問我羊精,道長斯够,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任喧锦,我火速辦了婚禮读规,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘燃少。我一直安慰自己束亏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布阵具。 她就那樣靜靜地躺著碍遍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪阳液。 梳的紋絲不亂的頭發(fā)上怕敬,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機(jī)與錄音帘皿,去河邊找鬼东跪。 笑死,一個胖子當(dāng)著我的面吹牛鹰溜,可吹牛的內(nèi)容都是我干的虽填。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼曹动,長吁一口氣:“原來是場噩夢啊……” “哼斋日!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仁期,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤桑驱,失蹤者是張志新(化名)和其女友劉穎竭恬,沒想到半個月后跛蛋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痊硕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年赊级,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岔绸。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡理逊,死狀恐怖橡伞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晋被,我是刑警寧澤兑徘,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站羡洛,受9級特大地震影響挂脑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜欲侮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一崭闲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧威蕉,春花似錦刁俭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至虑粥,卻和暖如春翘魄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舀奶。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工暑竟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人育勺。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓但荤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涧至。 傳聞我的和親對象是個殘疾皇子腹躁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

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