SpringMVC源碼的研究之dispatcherServlet

這幾天調(diào)試項(xiàng)目购桑,突然對(duì)于http請(qǐng)求如何傳到我的項(xiàng)目,然后找到對(duì)應(yīng)的控制方法產(chǎn)生了興趣菠隆,這部分的內(nèi)容比較多兵琳,本來(lái)想用一篇長(zhǎng)文來(lái)測(cè)試總結(jié)狂秘,現(xiàn)在還是先分點(diǎn)去記錄。


image.png

首先先介紹一下請(qǐng)求傳輸?shù)巾?xiàng)目的流程躯肌。Http請(qǐng)求是屬于應(yīng)用層的者春,請(qǐng)求的傳輸其實(shí)是在傳輸層,通過(guò)socket進(jìn)行傳輸?shù)絫omcat.
先介紹一些關(guān)于tomcat的知識(shí)清女。
tomcat目前的傳輸協(xié)議有四種钱烟,分別是:BIO, NIO,NIO2,APR

BIO協(xié)議依賴(lài)的類(lèi)是org.apache.coyote.http11.Http11Protocol
這個(gè)協(xié)議下,分為兩部分嫡丙,第一部分是acceptor拴袭,用于接收socket請(qǐng)求的
第二部分是worker線程池,用于處理socket請(qǐng)求的
BIO是阻塞流的IO,acceptor接收socket請(qǐng)求后發(fā)送給worker線程池處理曙博,如果線程池沒(méi)有空閑的線程拥刻,那么acceptor就會(huì)發(fā)生阻塞。

NIO協(xié)議依賴(lài)的類(lèi)是org.apache.coyote.http11.Http11NioProtocol
這個(gè)協(xié)議在BIO的基礎(chǔ)上增加了一個(gè)poller設(shè)置
acceptor接收socket請(qǐng)求后不是直接發(fā)送給線程池父泳,而是發(fā)送給poller般哼。在Poller中,維護(hù)了一個(gè)Selector對(duì)象惠窄;當(dāng)Poller從隊(duì)列中取出socket后蒸眠,注冊(cè)到該Selector中;然后通過(guò)遍歷Selector睬捶,找出其中可讀的socket黔宛,并使用Worker中的線程處理相應(yīng)請(qǐng)求。
通過(guò)BIO和NIO的描述擒贸,可以看出NIO在接收socket和處理socket的過(guò)程中臀晃,仍然會(huì)出現(xiàn)阻塞,不同的是介劫,NIO增加了一個(gè)Poller徽惋,基于這個(gè)區(qū)別,如果tomcat在高分發(fā)的情況下座韵,使用NIO可以提高Tomcat的工作效率

目前大多數(shù)HTTP請(qǐng)求使用的是長(zhǎng)連接(HTTP/1.1默認(rèn)keep-alive為true)险绘,而長(zhǎng)連接意味著,一個(gè)TCP的socket在當(dāng)前請(qǐng)求結(jié)束后誉碴,如果沒(méi)有新的請(qǐng)求到來(lái)宦棺,socket不會(huì)立馬釋放,而是等timeout后再釋放黔帕。如果使用BIO代咸,“讀取socket并交給Worker中的線程”這個(gè)過(guò)程是阻塞的,也就意味著在socket等待下一個(gè)請(qǐng)求或等待釋放的過(guò)程中成黄,處理這個(gè)socket的工作線程會(huì)一直被占用呐芥,無(wú)法釋放逻杖;因此Tomcat可以同時(shí)處理的socket數(shù)目不能超過(guò)最大線程數(shù),性能受到了極大限制思瘟。而使用NIO荸百,“讀取socket并交給Worker中的線程”這個(gè)過(guò)程是非阻塞的,當(dāng)socket在等待下一個(gè)請(qǐng)求或等待釋放時(shí)滨攻,并不會(huì)占用工作線程够话,因此Tomcat可以同時(shí)處理的socket數(shù)目遠(yuǎn)大于最大線程數(shù),并發(fā)性能大大提高光绕。

APR協(xié)議依賴(lài)的類(lèi)是org.apache.coyote.http11.Http11AprProtocol
APR是Apache Portable Runtime更鲁,是Apache可移植運(yùn)行庫(kù),利用本地庫(kù)可以實(shí)現(xiàn)高可擴(kuò)展性奇钞、高性能;Apr是在Tomcat上運(yùn)行高并發(fā)應(yīng)用的首選模式

配置相對(duì)應(yīng)的協(xié)議:

配置BIO的
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Protocol "
connectionTimeout="20000"
redirectPort="8443" />

配置NIO的
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol "
connectionTimeout="20000"
redirectPort="8443" />

配置APR的
<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol "
connectionTimeout="20000"
redirectPort="8443" />
注:Tomcat7中支持這3種漂坏,Tomcat8增加了對(duì)NIO2的支持景埃,而到了Tomcat8.5和Tomcat9.0,則去掉了對(duì)BIO的支持顶别。
如果沒(méi)有指定Protocal,則使用默認(rèn)值HTTP/1.1,其含義如下:在Tomcat7中谷徙,自動(dòng)選取使用BIO或APR(如果找到ARP需要的本地庫(kù),則使用ARP,否則使用BIO驯绎;在Tomcat8,自動(dòng)選取使用NIO或ARP(如果找到APR需要的本地庫(kù)完慧,則使用APR,否則使用NIO剩失。
參考鏈接:http://www.cnblogs.com/kismetv/p/7806063.html

socket請(qǐng)求經(jīng)過(guò)tomcat的線程處理后屈尼,會(huì)封裝成RequestFacade然后到web.xml配置文件
通過(guò)配置先初始化springMVC容器,進(jìn)入DispatcherServlet類(lèi)拴孤,進(jìn)行相關(guān)的初始化工作脾歧,這部分初始化我只了解了一點(diǎn)點(diǎn),先將我現(xiàn)在理解的寫(xiě)出來(lái)演熟,進(jìn)入這個(gè)類(lèi)鞭执,會(huì)先調(diào)用它的有參或者無(wú)參構(gòu)造方法,然后進(jìn)入它的父類(lèi)或者子類(lèi)的方法初始化spring容器芒粹,將handlerMethod和url進(jìn)行關(guān)聯(lián)兄纺,也就是在dispatcherServlet中有個(gè)onRefresh方法會(huì)執(zhí)行初始化方法initStrategies
該方法的結(jié)構(gòu)如下:

    protected void initStrategies(ApplicationContext context) {
           this.initMultipartResolver(context);
           this.initLocaleResolver(context);
           this.initThemeResolver(context);
           this.initHandlerMappings(context);
           this.initHandlerAdapters(context);
           this.initHandlerExceptionResolvers(context);
           this.initRequestToViewNameTranslator(context);
           this.initViewResolvers(context);
           this.initFlashMapManager(context);
       }

我了解的是HandlerMappings這部分,將handlerMappings初始化好會(huì)先調(diào)用一開(kāi)始結(jié)構(gòu)圖中的doService方法化漆,然后才到doDispatch方法估脆,doDispatch方法是springMVC的核心方法之一。

    rotected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
          HttpServletRequest processedRequest = request;
          HandlerExecutionChain mappedHandler = null;
          boolean multipartRequestParsed = false;
          WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

          try {
              try {
                  ModelAndView mv = null;
                  Object dispatchException = null;

                  try {
                        //判斷request是否是文件上傳的
                      processedRequest = this.checkMultipart(request);
                      multipartRequestParsed = processedRequest != request;
                      //通過(guò)HandlerMappings迭代器获三,選出合適的HandlerMapping旁蔼,然后調(diào)用這個(gè)對(duì)象的getHandler獲取Handler的執(zhí)行鏈
                      mappedHandler = this.getHandler(processedRequest);
                      if (mappedHandler == null || mappedHandler.getHandler() == null) {
                          this.noHandlerFound(processedRequest, response);
                          return;
                      }
                      //mappedHandler.getHandler()類(lèi)型是Object锨苏,但是可以轉(zhuǎn)換成HandlerMethod,之前初始化講到過(guò)這個(gè)部分
                      //通過(guò)handlerAdapter的方法supports來(lái)獲取相對(duì)應(yīng)的handlerAdapter(Hanlder的適配器)
                      HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                      String method = request.getMethod();
                      boolean isGet = "GET".equals(method);
                      if (isGet || "HEAD".equals(method)) {
                          long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                          if (this.logger.isDebugEnabled()) {
                              this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                          }

                          if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                              return;
                          }
                      }

                      //測(cè)試所有的攔截器,有一個(gè)失敗棺聊,則請(qǐng)求失敗
                      if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                          return;
                      }

                      //綁定請(qǐng)求到視圖上
                      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                      if (asyncManager.isConcurrentHandlingStarted()) {
                          return;
                      }

                      this.applyDefaultViewName(processedRequest, mv);
                      mappedHandler.applyPostHandle(processedRequest, response, mv);
                  } catch (Exception var20) {
                      dispatchException = var20;
                  } catch (Throwable var21) {
                      dispatchException = new NestedServletException("Handler dispatch failed", var21);
                  }

                  //傳輸?shù)角岸隧?yè)面
                  this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
              } catch (Exception var22) {
                  this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
              } catch (Throwable var23) {
                  this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
              }

          } finally {
              if (asyncManager.isConcurrentHandlingStarted()) {
                  if (mappedHandler != null) {
                      mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                  }
              } else if (multipartRequestParsed) {
                  this.cleanupMultipart(processedRequest);
              }

          }
      }

      private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
          if (mv != null && !mv.hasView()) {
              mv.setViewName(this.getDefaultViewName(request));
          }

      }

這部分代碼最重要的就是獲取HandlerExecutorChain和HandlerAdaptor這倆部分

HandlerExecutorChain是Handler的執(zhí)行鏈伞租,獲取對(duì)應(yīng)handler
首先進(jìn)行迭代HandlerMappings,然后根據(jù)傳入的request,調(diào)用HandlerMapping的方法getHandler(request),
該方法在AbstrateHandlerMapping類(lèi)下限佩,具體的代碼如下:

    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            //獲取內(nèi)部的handler
            Object handler = this.getHandlerInternal(request);
            if (handler == null) {
                handler = this.getDefaultHandler();
            }
    
            if (handler == null) {
                return null;
            } else {
                if (handler instanceof String) {
                    String handlerName = (String)handler;
                    handler = this.getApplicationContext().getBean(handlerName);
                }
    
                HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
                if (CorsUtils.isCorsRequest(request)) {
                    CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
                    CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
                    CorsConfiguration config = globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig;
                    executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
                }
    
                return executionChain;
            }
        }

這部分代碼中有個(gè)方法getHandlerInternal(request)方法是為了獲取內(nèi)部的handler的葵诈,這個(gè)方法在AbstrateHandlerMethodMapping類(lèi)中,這部分代碼如下:

 protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //獲取request映射到的url地址
    String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Looking up handler method for path " + lookupPath);
    }
  //設(shè)置讀鎖
    this.mappingRegistry.acquireReadLock();
    HandlerMethod var4;
    try {
      //取出該地址相關(guān)的handlerMethod
        HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
        if (this.logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                this.logger.debug("Returning handler method [" + handlerMethod + "]");
            } else {
                this.logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }

        var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
    } finally {
        this.mappingRegistry.releaseReadLock();
    }

    return var4;
}

之前初始化的時(shí)候祟同,我們說(shuō)了作喘,會(huì)將url和handler關(guān)聯(lián)起來(lái),這里代碼里的handlerMethod其實(shí)就是handler如下圖:

image.png

image.png

這個(gè)方法返回的變量也是設(shè)置成為了handler

獲取內(nèi)部handler方法getHandlerInternal(request)這部分講完了晕城,下一部分是方法getHandlerExecutionChain(handler,request),該方法是將相關(guān)的攔截器關(guān)聯(lián)到這個(gè)handler上泞坦,代碼如下:

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
           HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
           String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
           Iterator var5 = this.adaptedInterceptors.iterator();

           while(var5.hasNext()) {
               HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
               if (interceptor instanceof MappedInterceptor) {
                   MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
                   if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                       chain.addInterceptor(mappedInterceptor.getInterceptor());
                   }
               } else {
                   chain.addInterceptor(interceptor);
               }
           }

           return chain;
       }

到這里就完成了一個(gè)handlerExcetionChain的創(chuàng)建,下一步是找到相關(guān)的handler適配器

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
           Iterator var2 = this.handlerAdapters.iterator();

           HandlerAdapter ha;
           do {
               if (!var2.hasNext()) {
                   throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
               }

               ha = (HandlerAdapter)var2.next();
               if (this.logger.isTraceEnabled()) {
                   this.logger.trace("Testing handler adapter [" + ha + "]");
               }
           } while(!ha.supports(handler));

           return ha;
       }

這個(gè)方法參數(shù)是將前面獲得的handler執(zhí)行鏈的handler砖顷,調(diào)用handlerExcutionChain.getHandler()的方法返回一個(gè)object類(lèi)型
進(jìn)入handlerAdapter.supports(handler)方法


image.png

前面的條件是判斷handler是否是HandlerMethod的實(shí)例贰锁,這個(gè)地方我們回想一下,在前邊獲取HandlerMethod的時(shí)候滤蝠,我們將這個(gè)類(lèi)型轉(zhuǎn)換成了Object類(lèi)型豌熄,那么考慮一下,現(xiàn)在這種情況下物咳,handler是否依然是HandlerMethod的實(shí)例呢锣险?答案是肯定的,還是HandlerMethod的實(shí)例
測(cè)試代碼如下:


image.png

控制臺(tái)輸出如下:


image.png

因?yàn)镺bject是所有類(lèi)的父類(lèi)览闰,所以可以子類(lèi)轉(zhuǎn)換成父類(lèi)芯肤,也可以將父類(lèi)轉(zhuǎn)換成之前對(duì)應(yīng)的子類(lèi)。是同一個(gè)實(shí)例
好了言歸正傳压鉴,這個(gè)方法還有后一個(gè)條件纷妆,supportsInternal((HandlerMethod)handler)這個(gè)方法的代碼如下:
image.png

這個(gè)條件的作用是干嘛的,我現(xiàn)在還不清楚晴弃,看方法里的意思是只要是handlerMethod的參數(shù)掩幢,就會(huì)返回一個(gè)true

經(jīng)過(guò)這兩個(gè)條件的判斷,返回一個(gè)布爾值到getHandlerAdapter方法中上鞠,主要找到一個(gè)適配器际邻,就會(huì)自動(dòng)跳出循環(huán),返回handler適配器芍阎。

handler的執(zhí)行鏈和handler的適配器都有的情況下世曾,接下來(lái)是將handler執(zhí)行鏈?zhǔn)欠衲軌虺晒νㄟ^(guò)攔截器,只要有一個(gè)失敗谴咸,那么此次請(qǐng)求失敗轮听,代碼語(yǔ)句是:

        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
         }

然后通過(guò)handler適配器進(jìn)行視圖的處理骗露,handlerAdapter.handle(processedRequest, response, mappedHandler.getHandler())
返回一個(gè)ModelAndView的對(duì)象

最后通過(guò)
processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
方法將mv對(duì)象反饋到前端頁(yè)面。

總結(jié)
上邊說(shuō)了那么多血巍,如果沒(méi)看過(guò)源碼萧锉,應(yīng)該看起來(lái)比較吃力,下邊將本次的內(nèi)容進(jìn)行總結(jié)

1述寡、http請(qǐng)求在tcp層被封裝成socket請(qǐng)求發(fā)送給tomcat柿隙,tomcat用acceptor來(lái)接收socket請(qǐng)求,然后根據(jù)具體的協(xié)議來(lái)進(jìn)行相對(duì)應(yīng)的處理鲫凶,再交付給線程禀崖,tomcat將request打包成requestFacade,經(jīng)過(guò)doFilter重重的過(guò)濾器螟炫,到達(dá)HttpServlet類(lèi)波附,調(diào)用service(request,response)方法傳入請(qǐng)求和響應(yīng)對(duì)象,判斷請(qǐng)求類(lèi)型昼钻,然后調(diào)用doGet或者doPost方法叶雹,接著到FrameworkServlet的processRequest()方法中,調(diào)用doService(),再在這個(gè)方法中調(diào)用doDispatch()方法换吧,至此,完成了請(qǐng)求到分發(fā)器的步驟钥星。

2沾瓦、請(qǐng)求到達(dá)分發(fā)器,先判斷請(qǐng)求是否是文件上傳谦炒,文件上傳則請(qǐng)求失敗贯莺,否則通過(guò)HandlerMappings迭代器迭代出當(dāng)前請(qǐng)求對(duì)應(yīng)的handlerMapping,判斷是否匹配請(qǐng)求,需要調(diào)用handlerMapping.getHandler(request)方法宁改,在這個(gè)方法首先調(diào)用getHandlerInternal(request)判斷根據(jù)路徑是否能夠獲取到對(duì)應(yīng)的handler(handlerMethod)缕探,如果不能獲取到,則設(shè)置一個(gè)默認(rèn)的handler还蹲,注意在這個(gè)方法里邊加了一層讀鎖爹耗,接著調(diào)用getHandlerExecutionChain(handler,request)方法獲取handler的執(zhí)行鏈,這個(gè)方法實(shí)際上是給handler執(zhí)行鏈增加攔截器的作用谜喊,然后判斷一下是否跨域潭兽,最后返回匹配好的handler執(zhí)行鏈

3、handler執(zhí)行鏈獲取成功后斗遏,進(jìn)行第三個(gè)重要的步驟山卦,獲取handler的適配器,調(diào)用getHandlerAdapter()方法蟋座,傳入handlerExecutionChain.getHandler()作為參數(shù)夺荒,獲取適配器方法的內(nèi)部使用do...while(條件)的方式迭代出匹配的適配器速梗,判斷是否匹配钞啸,使用HandlerAdapter.supports(handler)作為條件,這個(gè)方法返回的是一個(gè)布爾值铸本,如果傳入的handler是HandlerMethod的實(shí)例肮雨,則返回true,跳出循環(huán)归敬,匹配成功酷含。

4、關(guān)于ModelAndView這塊汪茧,這部分內(nèi)容是根據(jù)HandlerExecutionChain和HandlerAdapter二者進(jìn)行進(jìn)一步的判定椅亚,然后反饋給前端信息,這部分我還沒(méi)怎么看舱污,現(xiàn)在無(wú)法總結(jié)呀舔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市扩灯,隨后出現(xiàn)的幾起案子媚赖,更是在濱河造成了極大的恐慌,老刑警劉巖珠插,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惧磺,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡捻撑,警方通過(guò)查閱死者的電腦和手機(jī)磨隘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)顾患,“玉大人番捂,你說(shuō)我怎么就攤上這事〗猓” “怎么了设预?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)犁河。 經(jīng)常有香客問(wèn)我鳖枕,道長(zhǎng),這世上最難降的妖魔是什么桨螺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任耕魄,我火速辦了婚禮,結(jié)果婚禮上彭谁,老公的妹妹穿的比我還像新娘吸奴。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布则奥。 她就那樣靜靜地躺著考润,像睡著了一般。 火紅的嫁衣襯著肌膚如雪读处。 梳的紋絲不亂的頭發(fā)上糊治,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音罚舱,去河邊找鬼井辜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛管闷,可吹牛的內(nèi)容都是我干的粥脚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼包个,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼刷允!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碧囊,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤树灶,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后糯而,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體天通,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年熄驼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了像寒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谜洽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吴叶,到底是詐尸還是另有隱情阐虚,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布蚌卤,位于F島的核電站实束,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏逊彭。R本人自食惡果不足惜咸灿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侮叮。 院中可真熱鬧避矢,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至砂沛,卻和暖如春烫扼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碍庵。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工映企, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人静浴。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓堰氓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親马绝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子豆赏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

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