Spring核心技術(shù)(六)——Spring中Bean的生命周期

前文已經(jīng)描述了Bean的作用域,本文將描述Bean的一些生命周期作用朱嘴,配置還有Bean的繼承。

定制Bean

生命周期回調(diào)

開發(fā)者通過實現(xiàn)Spring的InitializeingBeanDisposableBean接口,就可以讓容器來管理Bean的生命周期。容器會調(diào)用afterPropertiesSet()前和destroy()后才會允許Bean在初始化和銷毀Bean的時候執(zhí)行一些操作浸遗。

JSR-250的@PostConstruct@PreDestroy注解就是現(xiàn)代Spring應(yīng)用生命周期回調(diào)的最佳實踐。使用這些注解意味著Bean不在耦合在Spring特定的接口上箱亿。詳細(xì)內(nèi)容跛锌,后續(xù)將會介紹。
如果開發(fā)者不想使用JSR-250的注解届惋,仍然可以考慮使用init-methoddestroy-method定義來解耦髓帽。

內(nèi)部來說,Spring框架使用BeanPostProcessor的實現(xiàn)來處理任何接口的回調(diào)脑豹,BeanPostProcessor能夠找到并調(diào)用合適的方法郑藏。如果開發(fā)者需要一些Spring并不直接提供的生命周期行為,開發(fā)者可以自行實現(xiàn)一個BeanPostProcessor瘩欺。更多的信息可以參考后面的容器擴(kuò)展點必盖。

除了初始化和銷毀回調(diào),Spring管理的對象也實現(xiàn)了Lifecycle接口來讓管理的對象在容器的生命周期內(nèi)啟動和關(guān)閉俱饿。

生命周期回調(diào)在本節(jié)會進(jìn)行詳細(xì)描述歌粥。

初始化回調(diào)

org.springframework.beans.factory.InitializingBean接口允許Bean在所有的必要的依賴配置配置完成后來執(zhí)行初始化Bean的操作。InitializingBean接口中特指了一個方法:

void afterPropertiesSet() throws Exception;

Spring團(tuán)隊建議開發(fā)者不要使用InitializingBean接口拍埠,因為這樣會不必要的將代碼耦合到Spring之上失驶。而通過使用@PostConstruct注解或者指定一個POJO的實現(xiàn)方法,比實現(xiàn)接口要更好枣购。在基于XML的配置元數(shù)據(jù)上嬉探,開發(fā)者可以使用init-method屬性來指定一個沒有參數(shù)的方法。使用Java配置的開發(fā)者可以使用@Bean之中的initMethod屬性棉圈,比如如下:

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {

    public void init() {
        // do some initialization work
    }

}

與如下代碼一樣效果:

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean {

    public void afterPropertiesSet() {
        // do some initialization work
    }

}

但是前一個版本的代碼是沒有耦合到Spring的涩堤。

銷毀回調(diào)

實現(xiàn)了org.springframework.beans.factory.DisposableBean接口的Bean就能通讓容器通過回調(diào)來銷毀Bean所用的資源。DisposableBean接口包含了一個方法:

void destroy() throws Exception;

同InitializingBean同樣分瘾,Spring團(tuán)隊仍然不建議開發(fā)者來使用DisposableBean回調(diào)接口定躏,因為這樣會將開發(fā)者的代碼耦合到Spring代碼上。換種方式,比如使用@PreDestroy注解或者指定一個Bean支持的配置方法痊远,比如在基于XML的配置元數(shù)據(jù)中垮抗,開發(fā)者可以在Bean標(biāo)簽上指定destroy-method屬性。而在Java配置中碧聪,開發(fā)者可以配置@BeandestroyMethod冒版。

<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {

    public void cleanup() {
        // do some destruction work (like releasing pooled connections)
    }

}

上面的代碼配置和如下配置是等同的:

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean {

    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }

}

但是第一段代碼是沒有耦合到Spring的。

<bean/>標(biāo)簽的destroy-method可以被配置為特殊指定的值逞姿,來方便讓Spring能夠自動的檢查到close或者shutdown方法(可以實現(xiàn)java.lang.AutoCloseable或者java.io.Closeable都會匹配辞嗡。)這個特殊指定的值可以配置到<beans/>default-destroy-method來讓所有的Bean實現(xiàn)這個行為。

默認(rèn)初始化和銷毀方法

當(dāng)開發(fā)者不使用Spring特有的InitializingBeanDisposableBean回調(diào)接口來實現(xiàn)初始化和銷毀方法的時候滞造,開發(fā)者通常定義的方法名字都是好似init()续室,initialize()或者是dispose()等等。那么谒养,想這類的方法就可以標(biāo)準(zhǔn)化挺狰,來讓所有的開發(fā)者都使用一樣的名字來確保一致性。

開發(fā)者可以配置Spring容器來針對每一個Bean都查找這種名字的初始化和銷毀回調(diào)函數(shù)买窟。也就是說丰泊,任何的一個應(yīng)用開發(fā)者,都會在應(yīng)用的類中使用一個叫init()的初始化回調(diào)始绍,而不需要在每個Bean中定義init-method="init"這中屬性瞳购。Spring IoC容器會在Bean創(chuàng)建的時候調(diào)用那個方法(就如前面描述的標(biāo)準(zhǔn)生命周期一樣。)這個特性也強(qiáng)制開發(fā)者為其他的初始化以及銷毀回調(diào)函數(shù)使用同樣的名字亏推。

假設(shè)開發(fā)者的初始化回調(diào)方法名字為init()而銷毀的回調(diào)方法為destroy()学赛。那么開發(fā)者的類就會好似如下的代碼:

public class DefaultBlogService implements BlogService {

    private BlogDao blogDao;

    public void setBlogDao(BlogDao blogDao) {
        this.blogDao = blogDao;
    }

    // this is (unsurprisingly) the initialization callback method
    public void init() {
        if (this.blogDao == null) {
            throw new IllegalStateException("The [blogDao] property must be set.");
        }
    }

}
<beans default-init-method="init">

    <bean id="blogService" class="com.foo.DefaultBlogService">
        <property name="blogDao" ref="blogDao" />
    </bean>

</beans>

<beans/>標(biāo)簽上面的default-init-method屬性會讓Spring IoC容器識別叫做init的方法來作為Bean的初始化回調(diào)方法。當(dāng)Bean創(chuàng)建和裝載之后吞杭,如果Bean有這么一個方法的話盏浇,Spring容器就會在合適的時候調(diào)用。

類似的篇亭,開發(fā)者也可以配置默認(rèn)銷毀回調(diào)函數(shù)缠捌,基于XML的配置就在<beans/>標(biāo)簽上面使用default-destroy-method屬性锄贷。

當(dāng)存在一些Bean的類有了一些回調(diào)函數(shù)译蒂,而和配置的默認(rèn)回調(diào)函數(shù)不同的時候,開發(fā)者可以通過特指的方式來覆蓋掉默認(rèn)的回調(diào)函數(shù)谊却。以XML為例柔昼,就是通過使用<bean>標(biāo)簽的init-methoddestroy-method來覆蓋掉<beans/>中的配置。

Spring容器會做出如下保證炎辨,Bean會在裝載了所有的依賴以后捕透,立刻就開始執(zhí)行初始化回調(diào)。這樣的話,初始化回調(diào)只會在直接的Bean引用裝載好后調(diào)用乙嘀,而AOP攔截器還沒有應(yīng)用到Bean上末购。首先目標(biāo)Bean會完全初始化好,然后虎谢,AOP代理以及其攔截鏈才能應(yīng)用盟榴。如果目標(biāo)Bean以及代理是分開定義的,那么開發(fā)者的代碼甚至可以跳過AOP而直接和引用的Bean交互婴噩。因此擎场,在初始化方法中應(yīng)用攔截器會前后矛盾,因為這樣做耦合了目標(biāo)Bean的生命周期和代理/攔截器几莽,還會因為同Bean直接交互而產(chǎn)生奇怪的現(xiàn)象迅办。

聯(lián)合生命周期機(jī)制

在Spring 2.5之后,開發(fā)者有三種選擇來控制Bean的生命周期行為:

  • InitializingBeanDisposableBean回調(diào)接口
  • 自定義的init()以及destroy方法
  • 使用@PostConstruct以及@PreDestroy注解

開發(fā)者也可以在Bean上聯(lián)合這些機(jī)制一起使用

如果Bean配置了多個生命周期機(jī)制章蚣,而且每個機(jī)制配置了不同的方法名字站欺,那么每個配置的方法會按照后面描述的順序來執(zhí)行。然而究驴,如果配置了相同的名字镊绪,比如說初始化回調(diào)為init(),在不止一個生命周期機(jī)制配置為這個方法的情況下洒忧,這個方法只會執(zhí)行一次蝴韭。

如果一個Bean配置了多個生命周期機(jī)制,并且含有不同的方法名熙侍,執(zhí)行的順序如下:

  • 包含@PostConstruct注解的方法
  • InitializingBean接口中的afterPropertiesSet()方法
  • 自定義的init()方法

銷毀方法的執(zhí)行順序和初始化的執(zhí)行順序相同:

  • 包含@PreDestroy注解的方法
  • DisposableBean接口中的destroy()方法
  • 自定義的destroy()方法

啟動和關(guān)閉回調(diào)

Lifecycle接口中為任何有自己生命周期需求的對象定義了基本的方法(比如啟動和停止一些后臺進(jìn)程):

public interface Lifecycle {

    void start();

    void stop();

    boolean isRunning();

}

任何Spring管理的對象都可實現(xiàn)上面的接口榄鉴。那么當(dāng)ApplicationContext本身受到了啟動或者停止的信號時,ApplicationContext會通過委托LifecycleProcessor來串聯(lián)上下文中的Lifecycle的實現(xiàn)蛉抓。

public interface LifecycleProcessor extends Lifecycle {

    void onRefresh();

    void onClose();

}

從上面代碼我們可以發(fā)現(xiàn)LifecycleProcessorLifecycle接口的擴(kuò)展庆尘。LifecycleProcessor增加了另外的兩個方法來針對上下文的刷新和關(guān)閉做出反應(yīng)。

常規(guī)的org.springframework.context.Lifecycle接口只是為明確的開始/停止通知提供一個契約巷送,而并不表示在上下文刷新時自動開始驶忌。考慮實現(xiàn)org.springframework.context.SmartLifecycle接口可以取代在某個Bean的自動啟動過程(包括啟動階段)中的細(xì)粒度控制笑跛。同時付魔,停止通知并不能保證在銷毀之前出現(xiàn):在正常的關(guān)閉情況下,所有的LifecycleBean都會在銷毀回調(diào)準(zhǔn)備好之前收到停止停止飞蹂,然而几苍,在上下文存活期的熱刷新或者停止刷新嘗試的時候,只會調(diào)用銷毀方法陈哑。

啟動和關(guān)閉調(diào)用是很重要的妻坝。如果不同的Bean之間存在depends-on的關(guān)系的話伸眶,被依賴的一方需要更早的啟動,而且關(guān)閉的更早刽宪。然而厘贼,有的時候直接的依賴是未知的,而開發(fā)者僅僅知道哪一種類型需要更早進(jìn)行初始化圣拄。在這種情況下涂臣,SmartLifecycle接口定義了另一種選項,就是其父接口Phased中的getPhase()方法售担。

public interface Phased {

    int getPhase();

}
public interface SmartLifecycle extends Lifecycle, Phased {

    boolean isAutoStartup();

    void stop(Runnable callback);

}

當(dāng)啟動時赁遗,擁有最低的phased的對象優(yōu)先啟動,而當(dāng)關(guān)閉時族铆,是相反的順序岩四。因此,如果一個對象實現(xiàn)了SmartLifecycle然后令其getPhase()方法返回了Integer.MIN_VALUE的話哥攘,就會讓該對象最早啟動剖煌,而最晚銷毀。顯然逝淹,如果getPhase()方法返回了Integer.MAX_VALUE就說明了該對象會最晚啟動耕姊,而最早銷毀。當(dāng)考慮到使用phased的值得時候栅葡,也同時需要了解正常沒有實現(xiàn)SmartLifecycleLifecycle對象的默認(rèn)值茉兰,這個值為0。因此欣簇,任何負(fù)值將標(biāo)兵對象會在標(biāo)準(zhǔn)組件啟動之前啟動规脸,在標(biāo)準(zhǔn)組件銷毀以后再進(jìn)行銷毀。

SmartLifecycle接口也定義了一個stop的回調(diào)函數(shù)熊咽。任何實現(xiàn)了SmartLifecycle接口的函數(shù)都必須在關(guān)閉流程完成之后調(diào)用回調(diào)中的run()方法莫鸭。這樣做可以是能異步關(guān)閉。而LifecycleProcessor的默認(rèn)實現(xiàn)DefaultLifecycleProcessor會等到配置的超時時間之后再調(diào)用回調(diào)横殴。默認(rèn)的每一階段的超時時間為30秒被因。開發(fā)者可以通過定義一個叫做lifecycleProcessor的Bean來覆蓋默認(rèn)的生命周期處理器。如果開發(fā)者需要配置超時時間衫仑,可以通過如下代碼:

<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
    <!-- timeout value in milliseconds -->
    <property name="timeoutPerShutdownPhase" value="10000"/>
</bean>

和前文提到的梨与,LifecycleProcessor接口定義了回調(diào)方法來刷新和關(guān)閉山下文。關(guān)閉的話惑畴,如果stop()方法已經(jīng)明確調(diào)用了蛋欣,那么就會驅(qū)動關(guān)閉的流程航徙,但是如果是上下文關(guān)閉就不會發(fā)生這種情況如贷。而刷新的回調(diào)會使能SmartLifecycle的另一個特性陷虎。當(dāng)上下文刷新完畢(所有的對象已經(jīng)實例化并初始化),那么就會調(diào)用回調(diào)杠袱,默認(rèn)的生命周期處理器會檢查每一個SmartLifecycle對象的isAutoStartup()返回的Bool值尚猿。如果為真,對象將會自動啟動而不是等待明確的上下文調(diào)用楣富,或者調(diào)用自己的start()方法(不同于上下文刷新凿掂,標(biāo)準(zhǔn)的上下文實現(xiàn)是不會自動啟動的)。phased的值以及depends-on關(guān)系會決定對象啟動和銷毀的順序纹蝴。

在非Web應(yīng)用關(guān)閉Spring IoC容器

這一部分只是針對于非Web的應(yīng)用庄萎。Spring的基于web的ApplicationContext實現(xiàn)已經(jīng)有代碼在web應(yīng)用關(guān)閉的時候能夠優(yōu)雅的關(guān)閉Spring IoC容器。

如果開發(fā)者在非web應(yīng)用環(huán)境使用Spring IoC容器的話塘安, 比如糠涛,在桌面客戶端的環(huán)境下,開發(fā)者需要在JVM上注冊一個關(guān)閉的鉤子兼犯。來確保在關(guān)閉Spring IoC容器的時候能夠調(diào)用相關(guān)的銷毀方法來釋放掉對應(yīng)的資源忍捡。當(dāng)然,開發(fā)者也必須要正確的配置和實現(xiàn)那些銷毀回調(diào)切黔。

開發(fā)者可以在ConfigurableApplicationContext接口調(diào)用registerShutdownHook()來注冊銷毀的鉤子:

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Boot {

    public static void main(final String[] args) throws Exception {

        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
                new String []{"beans.xml"});

        // add a shutdown hook for the above context...
        ctx.registerShutdownHook();

        // app runs here...

        // main method exits, hook is called prior to the app shutting down...

    }
}

ApplicationContextAwareBeanNameAware

當(dāng)ApplicationContext在創(chuàng)建實現(xiàn)了org.springframework.context.ApplicationContextAware接口的對象時砸脊,該對象的實例會包含一個到ApplicationContext的引用。

public interface ApplicationContextAware {

    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

這樣Bean就能夠通過編程的方式操作和創(chuàng)建ApplicationContext了纬霞。通過ApplicationContext接口凌埂,或者通過將引用轉(zhuǎn)換成已知的接口的子類,比如ConfigurableApplicationContext就能夠顯式一些額外的功能诗芜。其中的一個用法就是可以通過編程的方式來獲取其他的Bean侨舆。有的時候這個能力很有用,然而绢陌,Spring團(tuán)隊推薦最好避免這樣做挨下,因為這樣會耦合代碼到Spring上,同時也沒有遵循IoC的風(fēng)格脐湾。其他的ApplicationContext的方法可以提供一些到資源的訪問臭笆,發(fā)布應(yīng)用事件,或者進(jìn)入MessageSource秤掌。這些信息在后續(xù)的針對ApplicationContext的描述中會講到愁铺。

在Spring 2.5版本,自動裝載也是獲得ApplicationContext的一種方式闻鉴。傳統(tǒng)的構(gòu)造函數(shù)和通過類型的裝載方式(前文Spring核心技術(shù)IoC容器(四)有相關(guān)描述)可以通過構(gòu)造函數(shù)或者是setter方法的方式注入茵乱。開發(fā)者也可以通過注解注入的方式使用更多的特性。

當(dāng)ApplicationContext創(chuàng)建了一個實現(xiàn)了org.springframework.beans.factory.BeanNameAware接口的類孟岛,那么這個類就可以針對其名字進(jìn)行配置瓶竭。

public interface BeanNameAware {

    void setBeanName(string name) throws BeansException;

}

這個回調(diào)的調(diào)用處于屬性配置完以后督勺,但是初始化回調(diào)之前,比如InitializingBeanafterPropertiesSet()方法以及自定義的初始化方法等斤贰。

其他Aware接口

除了上面描述的兩種Aware接口智哀,Spring還提供了一系列的Aware接口來讓Bean告訴容器,這些Bean需要一些具體的基礎(chǔ)設(shè)施信息荧恍。最重要的一些Aware接口都在下面表中進(jìn)行了描述:

名字 注入的依賴
ApplicationContextAware 聲明的ApplicationContext
ApplicationEventPlulisherAware ApplicationContext中的事件發(fā)布器
BeanClassLoaderAware 加載Bean使用的類加載器
BeanFactoryAware 聲明的BeanFactory
BeanNameAware Bean的名字
BootstrapContextAware 容器運行的資源適配器BootstrapContext瓷叫,通常僅在JCA環(huán)境下有效
LoadTimeWeaverAware 加載期間處理類定義的weaver
MessageSourceAware 解析消息的配置策略
NotificationPublisherAware Spring JMX通知發(fā)布器
PortletConfigAware 容器當(dāng)前運行的PortletConfig,僅在web下的Spring ApplicationContext中可見
PortletContextAware 容器當(dāng)前運行的PortletContext送巡,僅在web下的Spring ApplicationContext中可見
ResourceLoaderAware 配置的資源加載器
ServletConfigAware 容器當(dāng)前運行的ServletConfig摹菠,僅在web下的Spring ApplicationContext中可見
ServletContextAware 容器當(dāng)前運行的ServletContext,僅在web下的Spring ApplicationContext中可見

再次的聲明骗爆,上面這些接口的使用時違反IoC原則的辨嗽,除非必要,最好不要使用淮腾。

Bean繼承

Bean的定義可以包括很多的配置信息糟需,包括構(gòu)造參數(shù),屬性等等谷朝,也可以包括一些容器指定的信息洲押,比如初始化方法,工廠方法等等圆凰。子Bean會繼承父Bean的配置信息杈帐。子Bean也可以覆蓋父Bean的一些值,或者增加一些值专钉。通過定義父Bean和子Bean可以減少配置內(nèi)容挑童,是一種高效的模板性能。

如果開發(fā)者通過編程的方式跟ApplicationContext交流跃须,就會知道子Bean是通過ChildBeanDefinition類表示的站叼。大多數(shù)的開發(fā)者不需要再這個級別上來跟子Bean定義交互,只需要在ClassPathXmlApplicationContext中顯式的配置Bean就可以了菇民。當(dāng)使用基于XML的元數(shù)據(jù)配置的時候尽楔,開發(fā)者通過使用parent屬性來定義子Bean,如下所示:

<bean id="inheritedTestBean" abstract="true"
        class="org.springframework.beans.TestBean">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithDifferentClass"
        class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBean" init-method="initialize">
    <property name="name" value="override"/>
    <!-- the age property value of 1 will be inherited from parent -->
</bean>

如上述代碼所示第练,子Bean如果沒有配置任何內(nèi)容阔馋,是直接使用父Bean的配置信息的,當(dāng)然了娇掏,如果配置了呕寝,將會覆蓋父Bean的配置。

子Bean會繼承父Bean的作用范圍婴梧,構(gòu)造參數(shù)值下梢,屬性值客蹋,和覆蓋父Bean的方法,可以增加新的值怔球。任何的作用域,初始化方法浮还,銷毀方法竟坛,或者靜態(tài)工廠方法配置,開發(fā)者都可以覆蓋父Bean的配置钧舌。

有一些配置都是從子Bean定義中讀取的:depends-on担汤,自動裝載模式,依賴檢查洼冻,單例崭歧,延遲初始化。

前面的例子通過使用abstract標(biāo)簽來使父Bean抽象撞牢,如果父定義沒有指定類率碾,那么久需要使用屬性abstract如下:

<bean id="inheritedTestBeanWithoutClass" abstract="true">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBeanWithoutClass" init-method="initialize">
    <property name="name" value="override"/>
    <!-- age will inherit the value of 1 from the parent bean definition-->
</bean>

父Bean是無法被實例化的,因為它是不完整的屋彪,會被標(biāo)志位abstract所宰。當(dāng)使用abstract的時候,其配置就作為純模板來使用了畜挥。如果嘗試在abctract的父Bean中引用了其他的Bean或者調(diào)用getBean()都會返回錯誤仔粥。容器內(nèi)部的preInstantiateSingletons()方法會忽略掉那些定義為抽象的Bean。

ApplicationContext會默認(rèn)預(yù)初始化所有的單例蟹但。因此躯泰,如果開發(fā)者配置了一個父Bean作為模板,而且其定義了指定的類华糖,那么開發(fā)者就必須配置抽象屬性為true麦向,否則,應(yīng)用上下文會嘗試預(yù)初始化這個父Bean客叉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末磕蛇,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子十办,更是在濱河造成了極大的恐慌秀撇,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件向族,死亡現(xiàn)場離奇詭異呵燕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)件相,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門再扭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來氧苍,“玉大人,你說我怎么就攤上這事泛范∪门埃” “怎么了?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵罢荡,是天一觀的道長赡突。 經(jīng)常有香客問我,道長区赵,這世上最難降的妖魔是什么惭缰? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮笼才,結(jié)果婚禮上漱受,老公的妹妹穿的比我還像新娘。我一直安慰自己骡送,他們只是感情好昂羡,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著摔踱,像睡著了一般紧憾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昌渤,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天赴穗,我揣著相機(jī)與錄音,去河邊找鬼膀息。 笑死般眉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潜支。 我是一名探鬼主播甸赃,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冗酿!你這毒婦竟也來了埠对?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤裁替,失蹤者是張志新(化名)和其女友劉穎项玛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弱判,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡襟沮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片开伏。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡膀跌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出固灵,到底是詐尸還是另有隱情捅伤,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布巫玻,位于F島的核電站丛忆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏大审。R本人自食惡果不足惜蘸际,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一座哩、第九天 我趴在偏房一處隱蔽的房頂上張望徒扶。 院中可真熱鬧,春花似錦根穷、人聲如沸姜骡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圈澈。三九已至,卻和暖如春尘惧,著一層夾襖步出監(jiān)牢的瞬間康栈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工喷橙, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留啥么,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓贰逾,卻偏偏與公主長得像悬荣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子疙剑,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

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