Spring IoC分析

1 spring核心IoC

spring源碼版本 version 4.0.5

1.1 BeanFactory 和 ApplicationContext

spring IoC容器的核心的表現(xiàn)形式就是 BeanFactory和ApplicationContext

1.1.1 BeanFactory

  1. 可以通過(guò)getBean方法獲得指定的bean
  2. isSingleton 判斷指定的bean是不是單例的

主要是BeanFactory的接口中方法

其中有兩個(gè)BeanFactory的實(shí)現(xiàn)比較需要注意 DefaultListableBeanFactoryAbstractAutowireCapableBeanFactory巴帮。 使用比較多分飞。

1.1.2 ApplicationContext

其實(shí)使用編程的方式可以創(chuàng)建IoC,即創(chuàng)建factory 靶剑,然后對(duì)factory進(jìn)行各種設(shè)置再使用(參見(jiàn)本文1.2.2最后的示例)摸柄。但是spring提供了更加方便的ApplicationContext,同時(shí)還更加了一些額外的操作呻征。

  1. 支持不同的信息資源。ApplicationContext擴(kuò)展了MessageSource接口
  2. 訪問(wèn)資源。繼承自DefaultResourceLoader
  3. 支持應(yīng)用事件悠菜。繼承自接口ApplicationEventPublisher
  4. 附件服務(wù)

1.2 IoC 容器初始化過(guò)程

第一步:Resource定位過(guò)程。通過(guò)ResourceLoader的統(tǒng)一接口Resource找到BeanDefinition的資源定位败富。

第二步:BeanDefinition 載入悔醋。把用戶定義好的Bean轉(zhuǎn)換成IoC容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu)BeanDefinition。

第三步:向IoC容器注冊(cè)這些BeanDefinition的過(guò)程兽叮。調(diào)用BeanDefinitionRegistry.registerBeanDefinition實(shí)現(xiàn)芬骄。這個(gè)注冊(cè)過(guò)程把載入過(guò)程中解析的BeanDefinition向IoC注冊(cè)。實(shí)際上IoC內(nèi)部是將BeanDefinition注入好一個(gè)HashMap中鹦聪,通過(guò)這個(gè)HashMap來(lái)持有這些BeabDefinition的數(shù)據(jù)账阻。

這個(gè)過(guò)程中不包含依賴注入,依賴注入和bean定義(BeanDefinition)的載入是兩個(gè)獨(dú)立的過(guò)程泽本。 依賴注入一般發(fā)生在第一次使用getBean獲取bean的時(shí)候淘太,但是如果bean配置了lazyinit的話,會(huì)提前初始化规丽,不用等到第一次getBean觸發(fā)蒲牧。

1.2.1 BeanDefinition的資源定位

看BeanDefinition的資源定位,以FileSystemXmlApplicationContext為例赌莺,查看一下過(guò)程造成。
FileSystemXmlApplicationContext的構(gòu)造方法中,refresh() 方法啟動(dòng)IoC容器雄嚣。 幾種ApplicationContext的子類都是在構(gòu)造方法中refresh里面啟動(dòng)容器的。

方法調(diào)用鏈路:

AbstractApplicationContext.refresh()-->obtainFreshBeanFactory()-->refreshBeanFactory-->AbstractRefreshableApplicationContext.refreshBeanFactory()-->loadBeanDefinitions-->AbstractXmlApplicationContext.loadBeanDefinitions()

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    // 通過(guò)config獲取
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    // 通過(guò)字符串獲取
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

如果得到是String[] configLocations 則會(huì)最后進(jìn)入到 AbstractBeanDefinitionReader的public int loadBeanDefinitions(String location, Set<Resource> actualResources)喘蟆。此方法內(nèi)部把String 轉(zhuǎn)換成Resource缓升。 整個(gè)獲取BeanDefinition的過(guò)程就結(jié)束了,定位BeanDefinition的主要目的就是把資源位置轉(zhuǎn)換成可以處理的Resource

上面兩個(gè)分支最后都是走如下路徑去加載BeanDefinition

AbsractBeanDefinitionReader.loadBeanDefinitions(Resource... resources) --> XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource) (loadBeanDefinitions(EncodedResource encodedResource))

1.2.2 BeanDefinition的載入

在找到資源位子時(shí)候蕴轨,獲取到很多的Resources只有港谊,在需要根據(jù)資源類型,選擇不同類型的BeanDefinitionReader載入資源橙弱,例如Xml的配置文件歧寺,最后載入的時(shí)候就是XmlBeanDefinitionReader來(lái)執(zhí)行載入。

之前的說(shuō)到過(guò)棘脐,ApplicationContext的子類都是在構(gòu)造方法里面通過(guò)refresh方法啟動(dòng)容器的斜筐。所有BeanDefinition的資源定位和載入BeanDefinition的入口都是在refresh方法中。

核心入口:

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            // refresh前準(zhǔn)備工作
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            // 通知子類調(diào)用內(nèi)部 refresh bean factory的方法 refreshBeanFactory(),
            // 此refreshBeanFactory()是資源定位和載入的入口
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            // 設(shè)置beanFactory的標(biāo)準(zhǔn)上下文特征
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 設(shè)置beanFactory的后置處理
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 調(diào)用beanFactory的后處理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注冊(cè)bean 后處理器蛀缝,在bean創(chuàng)建的過(guò)程中調(diào)用
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 初始化上下文的消息資源
                initMessageSource();

                // Initialize event multicaster for this context.
                // 初始化上下文事件
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                // 利用子類初始化一些特殊bean
                onRefresh();

                // Check for listener beans and register them.
                // 檢查監(jiān)聽(tīng)器并向容器注冊(cè)這些監(jiān)聽(tīng)器
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 實(shí)例化所有(non-lazy-init)的單例組件
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 最后一步顷链,發(fā)布容器,結(jié)束refresh過(guò)程
                finishRefresh();
            }

            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                // 防止單例組件占用資源屈梁,在異常中銷毀
                destroyBeans();

                // Reset 'active' flag.
                // 設(shè)置'active'標(biāo)識(shí)
                cancelRefresh(ex);

                // Propagate exception to caller.
                // 向外層調(diào)用這拋出異常
                throw ex;
            }
        }
    }

前面步驟和查找resource一樣嗤练,xml形式的配置文件榛了,最后走到XmlBeanDefinitionReader中(定位資源中有提到,最后進(jìn)入XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)),進(jìn)入如下方法:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            // 將資源轉(zhuǎn)換成輸入流
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                // 在doLoadBeanDefinitions方法中實(shí)現(xiàn)BeanDefinition的載入
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

從輸入流中讀取bean的定義煞抬,從doLoadBeanDefinitions 方法進(jìn)入霜大,開(kāi)始載入BeanDefinition。在doLoadBeanDefinitions方法中通過(guò)InputSource和recource得到Document革答,緊接著調(diào)用registerBeanDefinitions战坤,實(shí)際調(diào)用到DefaultBeanDefinitionDocumentReader.registerBeanDefinitions-->doRegisterBeanDefinitions(root)

protected void doRegisterBeanDefinitions {
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!this.environment.acceptsProfiles(specifiedProfiles)) {
                return;
            }
        }
        
        // 任何嵌套的 <beans> 元素將會(huì)導(dǎo)致這個(gè)方法的循環(huán),
        // 為了正確的傳播和保存<beans>的default-*屬性蝗碎,追蹤當(dāng)前代理(可能為null)湖笨。
        // 創(chuàng)建一個(gè)新的代理對(duì)象,指向原來(lái)對(duì)象來(lái)達(dá)到回滾的目的蹦骑,最終重置this.delegate到原來(lái)的對(duì)象慈省。
        // 整個(gè)的表現(xiàn)模擬了一個(gè)代理?xiàng)#恍枰粋€(gè)代理
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(this.readerContext, root, parent);

        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);

        this.delegate = parent;
    }

再進(jìn)入parseBeanDefinitions解析眠菇。在parseBeanDefinitions中边败,如果是默認(rèn)的namespace就進(jìn)入parseDefaultElement(ele, delegate),如果不是就進(jìn)入delegate.parseCustomElement(ele),在parseDefaultElement中分別解析 importalias捎废、bean笑窜、beans ,其中beans會(huì)進(jìn)入遞歸,調(diào)用doRegisterBeanDefinitions登疗。bean是節(jié)點(diǎn)才是我創(chuàng)建bean的解析過(guò)程排截。其中bean分支左后進(jìn)入到DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 在BeanDefinitionParserDelegate中完成bean的解析,結(jié)果返回到BeanDefinitionHolder中
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        // BeanDefinitionParserDelegate在對(duì)holder進(jìn)行修飾(解析自定義的屬性)
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            // 向Ioc真正注冊(cè)裝飾之后的BeanDefinition實(shí)例
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        // BeanDefinition注冊(cè)完成之后發(fā)送消息
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

1.2.3 BeanDefinition在IoC容器的注冊(cè)

bean的注冊(cè)過(guò)程辐益,從上面解析過(guò)程完成之后断傲,就開(kāi)始注冊(cè)了,上面帶出顯示

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

進(jìn)入BeanDefinitionReaderUtils智政,registerBeanDefinition方法中最后調(diào)用BeanDefinitionRegistry接口的registerBeanDefinition认罩。查看DefaultListableBeanFactory中的實(shí)現(xiàn)

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                // 校驗(yàn)BeanDefinition
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }
        
        // private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
        // key是beanName,value是BeanDefinition
        synchronized (this.beanDefinitionMap) {
            BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) {
                // 如果同名的bean已經(jīng)注冊(cè),但是設(shè)置allowBeanDefinitionOverriding為false(即不允許定義重復(fù)),則拋出異常
                // 默認(rèn)的allowBeanDefinitionOverriding為true
                // 網(wǎng)上看到的設(shè)置allowBeanDefinitionOverriding的方法,但此方法有點(diǎn)局限在web項(xiàng)目中续捂,方案鏈接如下:
                // http://blog.csdn.net/zgmzyr/article/details/39380477
                // 那么還有沒(méi)有更好的辦法呢 垦垂?
                if (!this.allowBeanDefinitionOverriding) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
                }
                // 如果設(shè)置允許不定義不一致,但是重復(fù)的情況下牙瓢,判斷BeanDefition的role級(jí)別,日志提醒
                else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                    // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                                " with a framework-generated bean definition ': replacing [" +
                                oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
                else {
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding bean definition for bean '" + beanName +
                                "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
            }
            else {
                // 如果沒(méi)有重復(fù),添加beanName到list中四瘫,按照注冊(cè)順序排序
                this.beanDefinitionNames.add(beanName);
                this.frozenBeanDefinitionNames = null;
            }
            // 添加BeanDefinition到map中
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }

        resetBeanDefinition(beanName);
    }

回答上面提到的問(wèn)題稳析,如果設(shè)置allowBeanDefinitionOverriding還有什么方法诚纸,那就是使用IoC的釋放畦徘,方法換掉

@Test
public void testProgramWayIoC() {
    // 確定資源
    Resource res = new ClassPathResource("application.xml");
    // 創(chuàng)建一個(gè)BeanFactory,設(shè)置部分不想使用默認(rèn)值的屬性
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    factory.setAllowBeanDefinitionOverriding(false);
    // 創(chuàng)建BeanDefinitionReader
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    // 加載DeanDefinition并向IoC容器注冊(cè)
    reader.loadBeanDefinitions(res);
    // 使用bean
    TestBean test = factory.getBean("testBean",TestBean.class);
    test.testMethod();

}

雖然這樣可以,但是相比較來(lái)講,代碼注釋的地方提到的方案萍肆,相對(duì)更加實(shí)用。這里說(shuō)明這個(gè)只是說(shuō)可以用編程的方式使用IoC容器馏艾。

1.3 IoC的依賴注入

依賴注入的地方是在第一次使用getBean的時(shí)候注入的铁孵。但是當(dāng)設(shè)置了lazy-init的時(shí)候會(huì)在BeadDefinition載入的時(shí)候注入。

getBean是BeanFactory接口提供的方法岖沛,其實(shí)現(xiàn)在AbstractBeanFactory中

另外:ListableBeanFactory中有一個(gè)<T> T getBean(Class<T> requiredType) throws BeansException;的接口廊镜,在DefaultListableBeanFactory中實(shí)現(xiàn)。

依賴注入過(guò)程

AbstractBeanFactory.doCreateBean()-->AbstractBeanFactory.createBean()-->AbstractAutowireCapableBeanFactory.createBean()-->AbstractAutowireCapableBeanFactory.doCreateBean()-->AbstractAutowireCapableBeanFactory.createBeanInstance()-->initializeBean()-->registerDisposableBeanIfNecessary

1.4 前后處理器與容器的感知

1.4.1 BeanPostProcessor 與 BeanFactoryPostProcessor

BeanFactoryPostProcessor 是BeanFactory的后置處理器

public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

他只在beanFactory創(chuàng)建完成時(shí)候調(diào)用過(guò)一次,可以得到一個(gè)BeanFactory的子類吱雏。操作BeanFactory

BeanPostProcessor 是Bean的前后置處理器,可以在bean的初始化前后操作得滤。可是獲得beanName,修改Bean

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

這里面的兩個(gè)方法在所有的bean的初始化過(guò)程中都會(huì)調(diào)用,可以理解為一個(gè)攔截去的樣子慷暂。

InitializingBean 接口,主要實(shí)在bean實(shí)例化之后設(shè)置屬性血久,即各種感知器執(zhí)行完成之后

1.4.2 感知(Aware)

有些時(shí)候需要在bean使用IoC容器,對(duì)IoC容器進(jìn)行操作,這個(gè)時(shí)候就可以利用感知器的特點(diǎn)得到IoC進(jìn)行操作角骤。

幾種常用的感知器:

  1. BeanNameAware, 可以在Bean中得到它在IoC容器中的實(shí)例名稱
  2. BeanFactoryAware, 可以在Bean中得到bean所在的容器(beanFactory對(duì)象)优烧,從而在bean中直接使用IoC容器的服務(wù)又沾。
  3. ApplicationContextAware, 可以在bean中得到bean所在應(yīng)用的上下文,從而直接在Bean中使用上下文的服務(wù)。例如利用上下文getBean
  4. MessageSourceAware, 在Bean中得到消息源
  5. ApplicationEventPublisherAware,在Bean中得到上下文事件發(fā)布器,從而可以在Bean中發(fā)布應(yīng)用上下文事件
  6. ResourceLoaderAware, 在Bean中得到ResourceLoader,從而在bean中使用ResourceLoader加載外部對(duì)應(yīng)的Resource資源

1.5 Bean生命周期

bean的生命周期艾扮,整個(gè)過(guò)程就是先執(zhí)行BeanFactory的創(chuàng)建呛梆,如果有就不用再創(chuàng)建锐涯,在執(zhí)行beanFactory的后置處理器磕诊,再執(zhí)行實(shí)例化感知器。接下實(shí)例化。注入屬性霎终。調(diào)用各種Bean的感知器滞磺。調(diào)用bean的前后置處理器。如下圖:

圖片來(lái)源:http://www.cnblogs.com/zrtqsk/p/3735273.html

bean生命周期
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末莱褒,一起剝皮案震驚了整個(gè)濱河市击困,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌广凸,老刑警劉巖阅茶,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谅海,居然都是意外死亡脸哀,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)扭吁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)撞蜂,“玉大人,你說(shuō)我怎么就攤上這事侥袜◎蚬睿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵枫吧,是天一觀的道長(zhǎng)浦旱。 經(jīng)常有香客問(wèn)我,道長(zhǎng)由蘑,這世上最難降的妖魔是什么闽寡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮尼酿,結(jié)果婚禮上爷狈,老公的妹妹穿的比我還像新娘。我一直安慰自己裳擎,他們只是感情好涎永,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著鹿响,像睡著了一般羡微。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惶我,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天妈倔,我揣著相機(jī)與錄音,去河邊找鬼绸贡。 笑死盯蝴,一個(gè)胖子當(dāng)著我的面吹牛毅哗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捧挺,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼虑绵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了闽烙?” 一聲冷哼從身側(cè)響起翅睛,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎黑竞,沒(méi)想到半個(gè)月后捕发,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡很魂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年爬骤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莫换。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡霞玄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拉岁,到底是詐尸還是另有隱情坷剧,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布喊暖,位于F島的核電站惫企,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏陵叽。R本人自食惡果不足惜狞尔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巩掺。 院中可真熱鬧偏序,春花似錦、人聲如沸胖替。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)独令。三九已至端朵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間燃箭,已是汗流浹背冲呢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留招狸,地道東北人敬拓。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓瓤湘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親恩尾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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