從阿里跳槽來的工程師,連Spring容器與SpringMVC的容器的區(qū)別都不知道傻谁?

說起spring容器和SpringMVC容器孝治,很多剛接觸spring框架的同志都有點懵,甚至是一頭霧水审磁,分不清楚兩者的關(guān)系和區(qū)別谈飒。這倆容器呢雖然有必然的聯(lián)系,但是他們的區(qū)別也是有的态蒂。下面我就簡單描述下杭措。

一、前言

首先在我們開發(fā)中會與到各種各樣的容器钾恢,今天我們就說一下spring 容器與springmvc容器手素。Spring和SpringMVC作為Bean管理容器和MVC層的默認(rèn)框架鸳址,已被眾多web應(yīng)用采用。但是在實際應(yīng)用中泉懦,初級開發(fā)者常常會因?qū)pring和SpringMVC的配置失當(dāng)導(dǎo)致一些奇怪的異掣迨颍現(xiàn)象,比如Controller的方法無法攔截崩哩、Bean被多次加載等問題巡球,這種情況發(fā)生的根本原因在于開發(fā)者對Spring容器和SpringMVC容器之間的關(guān)系了解不夠深入。

在Spring整體框架的核心概念中邓嘹,容器的核心思想是管理Bean的整個生命周期辕漂。但在一個項目中,Spring容器往往不止一個吴超,最常見的場景就是在一個項目中引入Spring和SpringMVC這兩個框架,其本質(zhì)就是兩個容器鸯乃。首先 springmvc和spring它倆都是容器鲸阻,容器就是管理對象的地方,例如Tomcat缨睡,就是管理servlet對象的鸟悴,而springMVC容器和spring容器,就是管理bean對象的地方奖年,再說的直白點细诸,springmvc就是管理controller對象的容器,spring就是管理service和dao的容器陋守,這下你明白了吧震贵。所以我們在springmvc的配置文件里配置的掃描路徑就是controller的路徑,而spring的配置文件里自然配的就是service和dao的路徑

SpringMVC.xml文件所配置的路徑:

<context:component-scan base-package="com.jd.controller"/>

applicationContext-service.xml文件所配置的路徑:

<!--開啟注解掃描 掃描dao層和service層-->

<context:component-scan base-package="com.gx.dao,com.jd.service">

? ? <context:include-filter expression="org.springframework.stereotype.Service" type="annotation"/>

? ? <context:include-filter expression="org.springframework.stereotype.Repository" type="annotation"/>

</context:component-scan>

其次水评, spring容器和springmvc容器的關(guān)系是父子容器的關(guān)系猩系。spring容器是父容器,springmvc是子容器中燥。在子容器里可以訪問父容器里的對象寇甸,但是在父容器里不可以訪問子容器的對象,說的通俗點就是疗涉,在controller里可以訪問service對象拿霉,但是在service里不可以訪問controller對象

所以這么看的話,所有的bean咱扣,都是被spring或者springmvc容器管理的绽淘,他們可以直接注入。然后springMVC的攔截器也是springmvc容器管理的偏窝,所以在springmvc的攔截器里收恢,可以直接注入bean對象武学。

<!--SpringMVC 攔截器配置(可以多個)-->

<mvc:interceptors>

<!--配置攔截器-->

<mvc:interceptor>

<!--配置攔截的資源-->

<mvc:mapping path="/**"/>

<!--配置攔截器bean對象-->

<bean class="com.jd.interceptor.MyInterceptor1"/>

</mvc:interceptor>

</mvc:interceptors>

二、Spring容器伦意、SpringMVC容器與ServletContext之間的關(guān)系

在Web容器中配置Spring時火窒,你可能已經(jīng)司空見慣于web.xml文件中的以下配置代碼,下面我們以該代碼片段為基礎(chǔ)來了解Spring容器驮肉、SpringMVC容器與ServletContext之間的關(guān)系熏矿。要想理解這三者的關(guān)系,需要先熟悉Spring是怎樣在web容器中啟動起來的离钝。Spring的啟動過程其實就是其Spring IOC容器的啟動過程票编。特別地,對于web程序而言卵渴,IOC容器啟動過程即是建立上下文的過程慧域。

<web-app>

...

? ? <!-- 利用Spring提供的ContextLoaderListener監(jiān)聽器去監(jiān)聽ServletContext對象的創(chuàng)建,并初始化WebApplicationContext對象 -->

? ? <listener>

? ? ? ? <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

? ? </listener>

? ? <!-- Context Configuration locations for Spring XML files(默認(rèn)查找/WEB-INF/applicationContext.xml) -->

? ? <context-param>

? ? ? ? <param-name>contextConfigLocation</param-name>

? ? ? ? <param-value>classpath:applicationContext.xml</param-value>

? ? </context-param>

? ? <!-- 配置Spring MVC的前端控制器:DispatchcerServlet -->

? ? <servlet>

? ? ? ? <servlet-name>SpringMVC</servlet-name>

? ? ? ? <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

? ? ? ? <init-param>

? ? ? ? ? ? <param-name>contextConfigLocation</param-name>

? ? ? ? ? ? <param-value>classpath:springmvc.xml</param-value>

? ? ? ? </init-param>

? ? ? ? <load-on-startup>1</load-on-startup>

? ? </servlet>

? ? <servlet-mapping>

? ? ? ? <servlet-name>SpringMVC</servlet-name>

? ? ? ? <url-pattern>/</url-pattern>

? ? </servlet-mapping>

...

</web-app>

Spring的啟動過程

對于一個web應(yīng)用浪读,其部署在web容器中昔榴,web容器提供其一個全局的上下文環(huán)境,這個上下文就是ServletContext碘橘,其為后面的spring IoC容器提供宿主環(huán)境互订;

在web.xml中會提供有contextLoaderListener。在web容器啟動時痘拆,會觸發(fā)容器初始化事件仰禽,此時contextLoaderListener會監(jiān)聽到這個事件,其contextInitialized方法會被調(diào)用纺蛆。在這個方法中吐葵,spring會初始化一個啟動上下文,這個上下文被稱為根上下文犹撒,即WebApplicationContext折联。WebApplicationContext是一個接口類,確切的說识颊,其實際的實現(xiàn)類是XmlWebApplicationContext诚镰,它就是spring的IoC容器,其對應(yīng)的Bean定義的配置由web.xml中的<context-param>標(biāo)簽指定祥款。在這個IoC容器初始化完畢后清笨,Spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE為屬性Key,將其存儲到ServletContext中刃跛,便于獲瓤侔;

ContextLoaderListener監(jiān)聽器初始化完畢后桨昙,開始初始化web.xml中配置的Servlet检号,這個servlet可以配置多個腌歉,以最常見的DispatcherServlet為例,這個servlet實際上是一個標(biāo)準(zhǔn)的前端控制器齐苛,用以轉(zhuǎn)發(fā)翘盖、匹配、處理每個servlet請求凹蜂。DispatcherServlet上下文在初始化的時候會建立自己的IoC上下文馍驯,用以持有spring mvc相關(guān)的bean。特別地玛痊,在建立DispatcherServlet自己的IoC上下文前汰瘫,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作為自己上下文的parent上下文。有了這個parent上下文之后擂煞,再初始化自己持有的上下文混弥。這個DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化處理器映射对省、視圖解析等剑逃。這個servlet自己持有的上下文默認(rèn)實現(xiàn)類也是mlWebApplicationContext。初始化完畢后官辽,spring以與servlet的名字相關(guān)(此處不是簡單的以servlet名為Key,而是通過一些轉(zhuǎn)換粟瞬,具體可自行查看源碼)的屬性為屬性Key同仆,也將其存到ServletContext中,以便后續(xù)使用裙品。這樣每個servlet就持有自己的上下文俗批,即擁有自己獨立的bean空間,同時各個servlet共享相同的bean市怎,即根上下文(第2步中初始化的上下文)定義的那些bean岁忘。

Spring容器與SpringMVC的容器聯(lián)系與區(qū)別

ContextLoaderListener中創(chuàng)建Spring容器主要用于整個Web應(yīng)用程序需要共享的一些組件,比如DAO区匠、數(shù)據(jù)庫的ConnectionFactory等干像;而由DispatcherServlet創(chuàng)建的SpringMVC的容器主要用于和該Servlet相關(guān)的一些組件,比如Controller驰弄、ViewResovler等麻汰。它們之間的關(guān)系如下:

作用范圍

子容器(SpringMVC容器)可以訪問父容器(Spring容器)的Bean,父容器(Spring容器)不能訪問子容器(SpringMVC容器)的Bean戚篙。也就是說五鲫,當(dāng)在SpringMVC容器中g(shù)etBean時,如果在自己的容器中找不到對應(yīng)的bean岔擂,則會去父容器中去找位喂,這也解釋了為什么由SpringMVC容器創(chuàng)建的Controller可以獲取到Spring容器創(chuàng)建的Service組件的原因浪耘。

具體實現(xiàn)

在Spring的具體實現(xiàn)上,子容器和父容器都是通過ServletContext的setAttribute方法放到ServletContext中的塑崖。但是七冲,ContextLoaderListener會先于DispatcherServlet創(chuàng)建ApplicationContext,DispatcherServlet在創(chuàng)建ApplicationContext時會先找到由ContextLoaderListener所創(chuàng)建的ApplicationContext弃舒,再將后者的ApplicationContext作為參數(shù)傳給DispatcherServlet的ApplicationContext的setParent()方法癞埠。也就是說,子容器的創(chuàng)建依賴于父容器的創(chuàng)建聋呢,父容器先于子容器創(chuàng)建苗踪。在Spring源代碼中,你可以在FrameServlet.java中找到如下代碼:

wac.setParent(parent);

其中削锰,wac即為由DisptcherServlet創(chuàng)建的ApplicationContext通铲,而parent則為有ContextLoaderListener創(chuàng)建的ApplicationContext。此后器贩,框架又會調(diào)用ServletContext的setAttribute()方法將wac加入到ServletContext中颅夺。

三、Spring容器和SpringMVC容器的配置

在Spring整體框架的核心概念中蛹稍,容器是核心思想吧黄,就是用來管理Bean的整個生命周期的,而在一個項目中唆姐,容器不一定只有一個拗慨,Spring中可以包括多個容器,而且容器間有上下層關(guān)系奉芦,目前最常見的一種場景就是在一個項目中引入Spring和SpringMVC這兩個框架赵抢,其實就是兩個容器:Spring是根容器,SpringMVC是其子容器声功。在上文中烦却,我們提到,SpringMVC容器可以訪問Spring容器中的Bean先巴,Spring容器不能訪問SpringMVC容器的Bean其爵。但是,若開發(fā)者對Spring容器和SpringMVC容器之間的關(guān)系了解不夠深入伸蚯,常常會因配置失當(dāng)而導(dǎo)致同時配置Spring和SpringMVC時出現(xiàn)一些奇怪的異常醋闭,比如Controller的方法無法攔截、Bean被多次加載等問題朝卒。

在實際工程中证逻,一個項目中會包括很多配置,根據(jù)不同的業(yè)務(wù)模塊來劃分,我們一般思路是各負(fù)其責(zé)囚企,明確邊界丈咐,即:Spring根容器負(fù)責(zé)所有其他非controller的Bean的注冊,而SpringMVC只負(fù)責(zé)controller相關(guān)的Bean的注冊龙宏,下面我們演示這種配置方案棵逊。

(1). Spring容器配置

Spring根容器負(fù)責(zé)所有其他非controller的Bean的注冊:

<!-- 啟用注解掃描,并定義組件查找規(guī)則 银酗,除了@controller辆影,掃描所有的Bean -->

? ? <context:component-scan base-package="cn.edu.tju.rico">

? ? ? ? <context:exclude-filter type="annotation"

? ? ? ? ? ? expression="org.springframework.stereotype.Controller" />

? ? </context:component-scan>

(2). SpringMVC容器配置

SpringMVC只負(fù)責(zé)controller相關(guān)的Bean的注冊,其中@ControllerAdvice用于對控制器進行增強黍特,常用于實現(xiàn)全局的異常處理類:

? ? <!-- 啟用注解掃描蛙讥,并定義組件查找規(guī)則 ,mvc層只負(fù)責(zé)掃描@Controller灭衷、@ControllerAdvice -->

? ? <!-- base-package 如果多個次慢,用“,”分隔 -->

? ? <context:component-scan base-package="cn.edu.tju.rico"

? ? ? ? use-default-filters="false">

? ? ? ? <!-- 掃描@Controller -->

? ? ? ? <context:include-filter type="annotation"

? ? ? ? ? ? expression="org.springframework.stereotype.Controller" />

? ? ? ? <!--控制器增強,使一個Contoller成為全局的異常處理類翔曲,類中用@ExceptionHandler方法注解的方法可以處理所有Controller發(fā)生的異常 -->

? ? ? ? <context:include-filter type="annotation"

? ? ? ? ? ? expression="org.springframework.web.bind.annotation.ControllerAdvice" />

? ? </context:component-scan>

在<context:component-scan>中可以添加use-default-filters迫像,Spring配置中的use-default-filters用來指示是否自動掃描帶有@Component、@Repository瞳遍、@Service和@Controller的類闻妓。默認(rèn)為true,即默認(rèn)掃描掠械。如果想要過濾其中這四個注解中的一個纷闺,比如@Repository,可以添加<context:exclude-filter />子標(biāo)簽份蝴,如下:

<context:component-scan base-package="cn.edu.tju.rico" scoped-proxy="targetClass" use-default-filters="true">

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>

</context:component-scan>

而<context:include-filter/>子標(biāo)簽是用來添加掃描注解的:

<context:component-scan base-package="cn.edu.tju.rico" scoped-proxy="targetClass" use-default-filters="false">

<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>

</context:component-scan>

四、Spring容器和SpringMVC容器的配置失當(dāng)帶來的問題

問題描述

在一個項目中氓轰,想使用Spring AOP在Controller中切入一些邏輯婚夫,但發(fā)現(xiàn)不能切入到Controller的中,但可以切入到Service中署鸡。最初的配置情形如下:

1). Spring的配置文件application.xml包含了開啟AOP自動代理案糙、Service掃描配置以及Aspect的自動掃描配置,如下所示:

<aop:aspectj-autoproxy/>

<context:component-scan base-package="cn.edu.tju.rico">

2). Spring MVC的配置文件spring-mvc.xml主要內(nèi)容是Controller層的自動掃描配置靴庆。

<context:component-scan base-package="cn.edu.tju.rico.controller" />

3). 增強代碼為如下:

@Component

@Aspect

public class SecurityAspect {

? ? private static final String DEFAULT_TOKEN_NAME = "X-Token";

? ? private TokenManager tokenManager;

? ? @Resource(name = "tokenManager")

? ? public void setTokenManager(TokenManager tokenManager) {

? ? ? ? this.tokenManager = tokenManager;

? ? }

? ? @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")

? ? public Object execute(ProceedingJoinPoint pjp) throws Throwable {

? ? ? ? // 從切點上獲取目標(biāo)方法

? ? ? ? MethodSignature methodSignature = (MethodSignature) pjp.getSignature();

? ? ? ? Method method = methodSignature.getMethod();

? ? ? ? // 若目標(biāo)方法忽略了安全性檢查时捌,則直接調(diào)用目標(biāo)方法

? ? ? ? if (method.isAnnotationPresent(IgnoreSecurity.class)) {

? ? ? ? ? ? System.out

? ? ? ? ? ? ? ? ? ? .println("method.isAnnotationPresent(IgnoreSecurity.class) : "

? ? ? ? ? ? ? ? ? ? ? ? ? ? + method.isAnnotationPresent(IgnoreSecurity.class));

? ? ? ? ? ? return pjp.proceed();

? ? ? ? }

? ? ? ? // 從 request header 中獲取當(dāng)前 token

? ? ? ? String token = WebContext.getRequest().getHeader(DEFAULT_TOKEN_NAME);

? ? ? ? // 檢查 token 有效性

? ? ? ? if (!tokenManager.checkToken(token)) {

? ? ? ? ? ? String message = String.format("token [%s] is invalid", token);

? ? ? ? ? ? throw new TokenException(message);

? ? ? ? }

? ? ? ? // 調(diào)用目標(biāo)方法

? ? ? ? return pjp.proceed();

? ? }

}

4). 需要被代理的Controller如下:

@RestController

@RequestMapping("/tokens")

public class TokenController {

? ? private UserService userService;

? ? private TokenManager tokenManager;

? ? public UserService getUserService() {

? ? ? ? return userService;

? ? }

? ? @Resource(name = "userService")

? ? public void setUserService(UserService userService) {

? ? ? ? this.userService = userService;

? ? }

? ? public TokenManager getTokenManager() {

? ? ? ? return tokenManager;

? ? }

? ? @Resource(name = "tokenManager")

? ? public void setTokenManager(TokenManager tokenManager) {

? ? ? ? this.tokenManager = tokenManager;

? ? }

? ? @RequestMapping(method = RequestMethod.POST)

? ? @IgnoreSecurity

? ? public Response login(@RequestParam("uname") String uname,

? ? ? ? ? ? @RequestParam("passwd") String passwd) {

? ? ? ? boolean flag = userService.login(uname, passwd);

? ? ? ? if (flag) {

? ? ? ? ? ? String token = tokenManager.createToken(uname);

? ? ? ? ? ? System.out.println("**** Token **** : " + token);

? ? ? ? ? ? return new Response().success("Login Success...");

? ? ? ? }

? ? ? ? return new Response().failure("Login Failure...");

? ? }

? ? @RequestMapping(method = RequestMethod.DELETE)

? ? @IgnoreSecurity

? ? public Response logout(@RequestParam("uname") String uname) {

? ? ? ? tokenManager.deleteToken(uname);

? ? ? ? return new Response().success("Logout Success...");

? ? }

}

在運行過程中,發(fā)現(xiàn)這樣配置并沒有起作用炉抒,AOP配置不生效奢讨,沒有生成TokenController的代理。

解決方案

由上一節(jié)可知焰薄,原因有兩點:

Spring容器與SpringMVC容器分別基于各自的配置文件進行初始化拿诸,所以扒袖,在SpringMVC容器創(chuàng)建TokenController時,由于其沒有啟用AOP代理亩码,導(dǎo)致SpringMVC容器沒有為TokenController生成代理季率,所以沒有生效。

雖然父容器啟用了AOP代理描沟,但由于父子容器的獨立性飒泻,無濟于事。

因此吏廉,我們只需要在SpringMVC的配置文件中添加Aspect的自動掃描配置即可實現(xiàn)所要的效果泞遗。此外,一般地迟蜜,SpringMVC容器只管理Controller刹孔,剩下的Service、Repository 和 Component 由Spring容器只管理娜睛,不建議兩個容器上在管理Bean上發(fā)生交叉髓霞。因此,建議配置為:

SpringMVC 配置:

<aop:aspectj-autoproxy/>

<context:component-scan base-package="com.hodc.sdk.controller" />

Spring配置:

<context:annotation-config/>

<context:component-scan base-package="com.hodc.sdk">

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

總結(jié)

springmvc容器是spring容器的子容器畦戒,但是子容器可以父容器的bean, 但是父容器不能訪問子容器的bean方库。Spring容器和SpringMVC容器雖然是父容器與子容器的關(guān)系,但二者之間具有一定的獨立性障斋。具體來說纵潦,兩個容器基于各自的配置文件分別進行初始化,只有在子容器找不到對應(yīng)的Bean時垃环,才回去父容器中去找并加載

寫在最后

希望通過這篇文章能讓大家分清楚spring容器和SpringMVC容器的關(guān)系與區(qū)別邀层。雖然這些知識點都是老生常談,不否認(rèn)還是很多人分不清和不了解遂庄,但知識點不管是不是老生常談也都是需要掌握的寥院,畢竟基礎(chǔ)要打好,這樣才能有更高的成就賺到更多的錢呀涛目。好了本文到此結(jié)束了秸谢,希望能對鐵子們有幫助和收獲。喜歡的鐵子們可以點點贊和關(guān)注霹肝, 文章持續(xù)更新估蹄,也可以評論出你想看哪一塊技術(shù)。鐵子們的支持是我的動力沫换,創(chuàng)作離不開鐵子們的支持臭蚁,在此先感謝大家!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市刊棕,隨后出現(xiàn)的幾起案子炭晒,更是在濱河造成了極大的恐慌,老刑警劉巖甥角,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件网严,死亡現(xiàn)場離奇詭異,居然都是意外死亡嗤无,警方通過查閱死者的電腦和手機震束,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來当犯,“玉大人垢村,你說我怎么就攤上這事『课溃” “怎么了嘉栓?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拓诸。 經(jīng)常有香客問我侵佃,道長,這世上最難降的妖魔是什么奠支? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任馋辈,我火速辦了婚禮,結(jié)果婚禮上倍谜,老公的妹妹穿的比我還像新娘迈螟。我一直安慰自己,他們只是感情好尔崔,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布答毫。 她就那樣靜靜地躺著,像睡著了一般季春。 火紅的嫁衣襯著肌膚如雪洗搂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天鹤盒,我揣著相機與錄音,去河邊找鬼侦副。 笑死侦锯,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秦驯。 我是一名探鬼主播尺碰,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了亲桥?” 一聲冷哼從身側(cè)響起洛心,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎题篷,沒想到半個月后词身,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡番枚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年法严,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片葫笼。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡深啤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出路星,到底是詐尸還是另有隱情溯街,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布洋丐,位于F島的核電站呈昔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏垫挨。R本人自食惡果不足惜韩肝,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望九榔。 院中可真熱鬧哀峻,春花似錦、人聲如沸哲泊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽切威。三九已至育特,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間先朦,已是汗流浹背缰冤。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留喳魏,地道東北人棉浸。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓器躏,卻偏偏與公主長得像搂鲫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子每币,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

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