循環(huán)依賴

循環(huán)依賴

1主穗、循環(huán)依賴的介紹

循環(huán)依賴想许,bean之間相互持有各自的引用,最終形成閉環(huán)屁柏。比如

QQ截圖20180706104200.png

bean的實(shí)例化有如下三個(gè)步驟:

1、createBeanInstance 搜锰,生成原始對(duì)象

2维贺、popoulateBean告唆,進(jìn)行屬性注入

3域携、instantiateBean ,進(jìn)行init-method初始化和后置處理

由此鱼喉,當(dāng)生成A對(duì)象之后秀鞭,此時(shí)還未進(jìn)行屬性注入,檢測(cè)到A有B屬性扛禽,調(diào)用getBean(B b)獲取B锋边,

開始進(jìn)行B的實(shí)例化,B生成對(duì)象之后编曼,進(jìn)行屬性注入豆巨,檢測(cè)到B有A屬性,這個(gè)時(shí)候掐场,就產(chǎn)生了循環(huán)依賴往扔。

循環(huán)依賴會(huì)出現(xiàn)在下面幾種情況:

1)構(gòu)造函數(shù)的循環(huán)依賴

2)屬性的循環(huán)依賴,分為單例和原型兩種情況來分析

2熊户、循環(huán)依賴的處理方式

2.1萍膛、單例的循環(huán)依賴

spring處理循環(huán)依賴是這樣的:使用三級(jí)緩存。

/** Cache of singleton objects: bean name --> bean instance */
/** 緩存單例bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
/** 緩存單例bean的構(gòu)造工廠 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name --> bean instance */
/** 緩存提前曝光的單例bean 即還未完成完整實(shí)例化的bean */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

這三級(jí)緩存分別是:

singletonObjects:?jiǎn)卫龑?duì)象工廠的cache嚷堡,這里存儲(chǔ)的是完整實(shí)例化之后的bean

singletonFactories:?jiǎn)卫龑?duì)象的ObjectFactory蝗罗,該ObjectFactory返回的對(duì)象就是還未進(jìn)行popoulateBean的原始對(duì)象

earlySingletonObjects:提前曝光的單例bean,就是已經(jīng)本身還未進(jìn)行屬性注入的bean蝌戒,已經(jīng)作為其他的bean的屬性注入到該bean中了串塑,比如A還未進(jìn)行屬性注入,但是被B引用到了北苟,注入到B中桩匪,此時(shí)就將A放到提前曝光的單例bean緩存earlySingletonObjects中。

針對(duì)單例進(jìn)行源碼分析:

假設(shè)A->B,B->A,以上bean對(duì)象存在循環(huán)依賴:

調(diào)用getBean(A)->AbstractBeanFactory.doGetBean(省略相關(guān)代碼粹淋,留下關(guān)鍵代碼)

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    //針對(duì)beanName進(jìn)行處理
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    //獲取緩存的單例bean
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            //獲取的bean當(dāng)前處于創(chuàng)建狀態(tài)吸祟,即還未初始化完成,僅僅是new出來而已桃移,屬性還沒注入完成屋匕,且存在依賴循環(huán)
            //比如A->B,B->A
            //1借杰、getBean(A),獲取到A的實(shí)例过吻,此時(shí)還未進(jìn)行注入
            //2、開始注入,發(fā)現(xiàn)B屬性纤虽,開始getBean(B)乳绕,獲取到B的實(shí)例
            //3、開始對(duì)B注入逼纸,發(fā)現(xiàn)A屬性洋措,獲取到還未注入完成的A,即處于isSingletonCurrentlyInCreation的A
            //4杰刽、完成B的注入菠发,getBean(B)完成,然后A的注入也完成贺嫂,也就是在構(gòu)建單例的時(shí)候滓鸠,會(huì)將還未完成注入的A提前暴露,便于B完成注入
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        //當(dāng)用戶輸入的beanname前綴為“&”第喳,要求獲取的是factoryBean
        //否則獲取的就是普通的bean
        //這里就是對(duì)這兩種情況進(jìn)行處理
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // Create bean instance.
        //單例的處理
        //首先創(chuàng)建beanFactory,即ObjectBeanFacotry并實(shí)現(xiàn)getObject接口
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    // Explicitly remove instance from singleton cache: It might have been put there
                    // eagerly by the creation process, to allow for circular reference resolution.
                    // Also remove any beans that received a temporary reference to the bean.
                    destroySingleton(beanName);
                    throw ex;
                }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
    }

    return (T) bean;
}

由于A是第一次初始化糜俗,故會(huì)調(diào)用getSingleton方法:

sharedInstance = getSingleton(beanName, () -> {
   try {
      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
      // Explicitly remove instance from singleton cache: It might have been put there
      // eagerly by the creation process, to allow for circular reference resolution.
      // Also remove any beans that received a temporary reference to the bean.
      destroySingleton(beanName);
      throw ex;
   }
});

這里調(diào)用的是DefaultSingletonBeanRegistry.getSingleton

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   //鎖定singletonObjects,確保線程安全
   synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         //對(duì)于正在創(chuàng)建狀態(tài)的單例bean曲饱,再次進(jìn)入此方法悠抹,拋出異常
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                  "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
         }
         //進(jìn)行創(chuàng)建狀態(tài)的記錄 this.singletonsCurrentlyInCreation.add(beanName)
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // Has the singleton object implicitly appeared in the meantime ->
            // if yes, proceed with it since the exception indicates that state.
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throw ex;
            }
         }
         catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) {
                  ex.addRelatedCause(suppressedException);
               }
            }
            throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            //進(jìn)行創(chuàng)建狀態(tài)的移除 this.singletonsCurrentlyInCreation.remove(beanName)
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            //將bean加載到對(duì)應(yīng)的容器中,并對(duì)相關(guān)輔助容器進(jìn)行bean的刪除
            //this.singletonObjects.put(beanName, singletonObject);
            //this.singletonFactories.remove(beanName);
            //this.earlySingletonObjects.remove(beanName);
            //this.registeredSingletons.add(beanName);
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

這個(gè)方法一共做了這么幾件事:

1扩淀、在創(chuàng)建實(shí)例之前锌钮,記錄正在創(chuàng)建狀態(tài),singletonsCurrentlyInCreation.add(beanName)

2引矩、創(chuàng)建實(shí)例梁丘,調(diào)用singletonFactory.getObject();

3、移除正在創(chuàng)建狀態(tài)旺韭,this.singletonsCurrentlyInCreation.remove(beanName)

4氛谜、將該bean緩存到單例緩存容器, this.singletonObjects.put(beanName, singletonObject);并且從相關(guān)的輔助容器刪除区端,如singletonFactories和earlySingletonObjects

進(jìn)入到singletonFactory.getObject();,這里調(diào)用的是AbstractAutowireCapableBeanFactory.doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   final Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
      mbd.resolvedTargetType = beanType;
   }

   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   //如果當(dāng)前是單例值漫,且允許循環(huán)依賴而且當(dāng)前bean處于創(chuàng)建狀態(tài)
   //this.singletonFactories.put(beanName, singletonFactory);三級(jí)緩存添加實(shí)例對(duì)象工廠
   //this.earlySingletonObjects.remove(beanName);二級(jí)緩存刪除實(shí)例對(duì)象
   //this.registeredSingletons.add(beanName);
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
      if (logger.isDebugEnabled()) {
         logger.debug("Eagerly caching bean '" + beanName +
               "' to allow for resolving potential circular references");
      }
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      populateBean(beanName, mbd, instanceWrapper);
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
      if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
         throw (BeanCreationException) ex;
      }
      else {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
      }
   }

   if (earlySingletonExposure) {
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {
         if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
         }
         else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {
               if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                  actualDependentBeans.add(dependentBean);
               }
            }
            if (!actualDependentBeans.isEmpty()) {
               throw new BeanCurrentlyInCreationException(beanName,
                     "Bean with name '" + beanName + "' has been injected into other beans [" +
                     StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                     "] in its raw version as part of a circular reference, but has eventually been " +
                     "wrapped. This means that said other beans do not use the final version of the " +
                     "bean. This is often the result of over-eager type matching - consider using " +
                     "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
            }
         }
      }
   }

   // Register bean as disposable.
   try {
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }

   return exposedObject;
}

這個(gè)方法一共做了這么幾件事:

1、實(shí)例化bean

  if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

2织盼、如果當(dāng)前允許循環(huán)依賴且當(dāng)前bean是單例而且處于創(chuàng)建狀態(tài)杨何,將此單例的ObjectFactory加入到singletonFactories,且此factory返回的bean對(duì)象就是當(dāng)前實(shí)例化好的bean

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

3沥邻、進(jìn)行屬性注入populateBean(beanName, mbd, instanceWrapper);

4危虱、instantiateBean ,進(jìn)行init-method初始化和后置處理

從這里可以看出來唐全,在pupulateBean之前埃跷,singletonFactories存儲(chǔ)了該bean的factory蕊玷,然后進(jìn)行pupulateBean,發(fā)現(xiàn)B是A的屬性弥雹,然后調(diào)用getBean(B)對(duì)B進(jìn)行實(shí)例化垃帅,重復(fù)上面的步驟到B的屬性注入環(huán)節(jié),發(fā)現(xiàn)A是B的屬性剪勿,這個(gè)時(shí)候贸诚,再次調(diào)用getBean(A),此時(shí)緩存中已經(jīng)有了A了

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

   //針對(duì)beanName進(jìn)行處理
   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   //獲取緩存的單例bean
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         //獲取的bean當(dāng)前處于創(chuàng)建狀態(tài),即還未初始化完成厕吉,僅僅是new出來而已赦颇,屬性還沒注入完成,且存在依賴循環(huán)
         //比如A->B赴涵,B->A
         //1、getBean(A),獲取到A的實(shí)例订讼,此時(shí)還未進(jìn)行注入
         //2髓窜、開始注入,發(fā)現(xiàn)B屬性欺殿,開始getBean(B)寄纵,獲取到B的實(shí)例
         //3、開始對(duì)B注入脖苏,發(fā)現(xiàn)A屬性程拭,獲取到還未注入完成的A,即處于isSingletonCurrentlyInCreation的A
         //4棍潘、完成B的注入恃鞋,getBean(B)完成,然后A的注入也完成亦歉,也就是在構(gòu)建單例的時(shí)候恤浪,會(huì)將還未完成注入的A提前暴露,便于B完成注入
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      //當(dāng)用戶輸入的beanname前綴為“&”肴楷,要求獲取的是factoryBean
      //否則獲取的就是普通的bean
      //這里就是對(duì)這兩種情況進(jìn)行處理
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
   return (T)bean;
 }

重點(diǎn)關(guān)注

   //獲取緩存的單例bean
   Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   /** 從singletonObjects獲取bean實(shí)例 */
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         /** 如果singletonObjects還沒有此bean水由,有兩種情況
          * 1、說明還未完全實(shí)例化赛蔫,正在創(chuàng)建狀態(tài)砂客,先從earlySingletonObjects獲取
          * 2、該bean還沒開始創(chuàng)建
          */
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
            /** 如果earlySingletonObjects還沒有此bean呵恢,有兩種情況
             * 1鞠值、說明還未曝光,即被其他bean注入渗钉,正在創(chuàng)建狀態(tài)齿诉,先從singletonFactories獲取
             * 2、該bean還沒開始創(chuàng)建*/
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               /** factory不為空,說明處于正在創(chuàng)建狀態(tài)粤剧,且還未被其他bean注入歇竟,從singletonObject取出bean
                * 1、將此bean放到提前曝光的緩存earlySingletonObjects中
                * 2抵恋、同時(shí)刪除在singletonFactories的緩存
                * */
               singletonObject = singletonFactory.getObject();
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

這個(gè)方法做了這么一件事焕议,逐步從三級(jí)緩存中獲取bean:

1)先到singletonObjects獲取,如果有表示實(shí)例化已經(jīng)完成弧关;

2)否則到earlySingletonObjects獲取盅安,如果有表示已經(jīng)有bean,且存在循環(huán)依賴世囊,將此bean作為屬性注入了

3)否則到singletonFactories獲取别瞭,如果存在循環(huán)依賴,且此屬性是第一次被其他bean作為屬性注入

這里B將A第一次作為屬性注入株憾,返回的是singletonFactories生成的bean蝙寨,也就是剛剛未完成實(shí)例化的A對(duì)象。

此時(shí)A的引用從singletonFactories轉(zhuǎn)移到earlySingletonObjects嗤瞎,表示已經(jīng)被曝光了墙歪。

此時(shí)B已經(jīng)完成屬性注入,到這里贝奇,其實(shí)B已經(jīng)完成了實(shí)例化虹菲,也可以說A完成了屬性注入了。

接下來回顧獲取A的這個(gè)方法DefaultSingletonBeanRegistry.getSingleton掉瞳,其實(shí)到了這里毕源,我們也只是完成了singletonFactory.getObject(),最后一步陕习,將A放在singletonObjects中:

 //將bean加載到對(duì)應(yīng)的容器中脑豹,并對(duì)相關(guān)輔助容器進(jìn)行bean的刪除
 //this.singletonObjects.put(beanName, singletonObject);
 //this.singletonFactories.remove(beanName);
 //this.earlySingletonObjects.remove(beanName);
 //this.registeredSingletons.add(beanName);
 addSingleton(beanName, singletonObject);

至此,單例的循環(huán)依賴得到了解決衡查。

其實(shí)瘩欺,解決循環(huán)依賴就在于未完成實(shí)例化的Bean在三級(jí)緩存中的轉(zhuǎn)移:

1)A剛實(shí)例化,未進(jìn)行屬性注入拌牲,添加到singletonFactories

2)正在屬性注入B俱饿,且同時(shí)第一次被B所依賴,B在屬性注入的時(shí)候?qū)由singletonFactories轉(zhuǎn)移至earlySingletonObjects

3)待B屬性注入完成塌忽,完成實(shí)例化拍埠,A也就完成了實(shí)例化,此時(shí)土居,將A轉(zhuǎn)移至singletonObjects

同理枣购,B亦是如此

2.2嬉探、構(gòu)造方法的循環(huán)依賴

由于此循環(huán)依賴是在對(duì)象實(shí)例化的時(shí)候進(jìn)行的,也就是說這種依賴是無法像單例一樣生成對(duì)象棉圈,那么這種循環(huán)依賴也只能通過拋出異常處理

2.3涩堤、原型模式的循環(huán)依賴

由于原型模式不像單例一樣會(huì)提供緩存來進(jìn)行輔助存儲(chǔ)未完整實(shí)例化的bean,故spring的處理也是直接拋出異常

//對(duì)于原型模式的循環(huán)依賴分瘾,直接拋出異常
if (isPrototypeCurrentlyInCreation(beanName)) {
   throw new BeanCurrentlyInCreationException(beanName);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末胎围,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子德召,更是在濱河造成了極大的恐慌白魂,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件上岗,死亡現(xiàn)場(chǎng)離奇詭異福荸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)肴掷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門敬锐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捆等,你說我怎么就攤上這事⌒遥” “怎么了栋烤?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)挺狰。 經(jīng)常有香客問我明郭,道長(zhǎng),這世上最難降的妖魔是什么丰泊? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任薯定,我火速辦了婚禮,結(jié)果婚禮上瞳购,老公的妹妹穿的比我還像新娘话侄。我一直安慰自己,他們只是感情好学赛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布年堆。 她就那樣靜靜地躺著,像睡著了一般盏浇。 火紅的嫁衣襯著肌膚如雪变丧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天绢掰,我揣著相機(jī)與錄音痒蓬,去河邊找鬼童擎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛攻晒,可吹牛的內(nèi)容都是我干的顾复。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼炎辨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼捕透!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起碴萧,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤乙嘀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后破喻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虎谢,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年曹质,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了婴噩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡羽德,死狀恐怖几莽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宅静,我是刑警寧澤章蚣,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站姨夹,受9級(jí)特大地震影響纤垂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜磷账,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一峭沦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逃糟,春花似錦吼鱼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至剃诅,卻和暖如春巷送,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背矛辕。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工笑跛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留付魔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓飞蹂,卻偏偏與公主長(zhǎng)得像几苍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陈哑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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