spring源碼分析8----@scope對(duì)bean的影響

作者:shihuaping0918@163.com轉(zhuǎn)載請(qǐng)注明作者

scope是用來(lái)定義spring如何創(chuàng)建bean的。bean默認(rèn)是singleton涂乌,在容器中只有一個(gè)實(shí)例械筛,名字就提示了敢艰,是設(shè)計(jì)模式里的單件,或者叫單例俊抵。還有一種是prototype谁不,可以創(chuàng)建多個(gè)實(shí)例。對(duì)于singleton徽诲,無(wú)所謂生命周期刹帕,反正容器在它就在,頂多是關(guān)注一下它是在哪里實(shí)例化的谎替。只有prototype類型的才有真正意義上的生命周期偷溺。這篇文章就帶大家來(lái)看一下prototype類型的bean的生命周期。

prototype類型的bean可以通過(guò)應(yīng)用上下文獲取時(shí)創(chuàng)建钱贯,也可以在注入時(shí)創(chuàng)建挫掏。先看一下應(yīng)用上下文獲取時(shí),它是怎么創(chuàng)建的秩命。因?yàn)樗蟹椒ㄗ鳛槿肟谖竟玻雌饋?lái)比較直觀。在之前的文章中弃锐,其實(shí)已經(jīng)分析過(guò)應(yīng)用上下文相關(guān)的代碼了袄友,也就是applicationContext相關(guān)的代碼,其中有一個(gè)類對(duì)register factory的方法做了一層封裝霹菊,用意就是在調(diào)register factory方法時(shí)剧蚣,先做一下判斷。下面直接去AbstractApplicationContext里看方法。

@Override
public Object getBean(String name) throws BeansException { //看它就好了
   assertBeanFactoryActive(); //同下
   return getBeanFactory().getBean(name);
}

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
   assertBeanFactoryActive(); //同上
   return getBeanFactory().getBean(name, requiredType);
}

@Override
public Object getBean(String name, Object... args) throws BeansException {
   assertBeanFactoryActive(); //同上
   return getBeanFactory().getBean(name, args);
}

@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
   assertBeanFactoryActive(); //同上
   return getBeanFactory().getBean(requiredType);
}

@Override
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
   assertBeanFactoryActive(); //同上
   return getBeanFactory().getBean(requiredType, args);
}

前面的文章里介紹過(guò)getBeanFactory獲取的是DefaultListableBeanFactory券敌,到這個(gè)類里去找getBean方法,getBean位于AbstractBeanFactory里面柳洋。

@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}

注意參數(shù)待诅,要關(guān)注參數(shù)值,后續(xù)的代碼看起來(lái)才有重點(diǎn)熊镣。

/**
 * Return an instance, which may be shared or independent, of the specified bean.
 * @param name the name of the bean to retrieve
 * @param requiredType the required type of the bean to retrieve
 * @param args arguments to use when creating a bean instance using explicit arguments
 * (only applied when creating a new instance as opposed to retrieving an existing one)
 * @param typeCheckOnly whether the instance is obtained for a type check,
 * not for actual use
 * @return an instance of the bean
 * @throws BeansException if the bean could not be created
 */
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//requiredType=null,args=null,typeCheckOnly=false卑雁,注意參數(shù)
   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) { //我們要看的是prototype,single這一段跳過(guò)
      if (logger.isTraceEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else { //代碼進(jìn)了這里,非singleton的類型
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // Check if bean definition exists in this factory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      //如果有父類廠绪囱,且當(dāng)前類廠中沒(méi)有這個(gè)bean测蹲,就到父類廠中查找,不進(jìn)這個(gè)條件里面
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                  nameToLookup, requiredType, args, typeCheckOnly);
         }
         else if (args != null) { //args==null鬼吵,不進(jìn)
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else if (requiredType != null) { //requiredType==null扣甲,不進(jìn)
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
         else {
            return (T) parentBeanFactory.getBean(nameToLookup);
         }
      }

      if (!typeCheckOnly) { //注意進(jìn)來(lái)的參數(shù)typeCheckOnly==false
         markBeanAsCreated(beanName); 
      }

      try {
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // Guarantee initialization of beans that the current bean depends on.
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {  //創(chuàng)建父類,屬性成員類齿椅,等等
            for (String dep : dependsOn) {
               if (isDependent(beanName, dep)) { //循環(huán)依賴琉挖,拋異常
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               registerDependentBean(dep, beanName);
               try {
                  getBean(dep);
               }
               catch (NoSuchBeanDefinitionException ex) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
               }
            }
         }

         // Create bean instance.
         if (mbd.isSingleton()) { //singleton類型跳過(guò)
            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);
         }

         else if (mbd.isPrototype()) {  //我們想要的prototype代碼流程,直接創(chuàng)建一個(gè)新的bean
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName); //tls中添加當(dāng)前創(chuàng)建的bean信息
               prototypeInstance = createBean(beanName, mbd, args); //在這里創(chuàng)建了bean
            }
            finally {
               afterPrototypeCreation(beanName); //tls中清除當(dāng)前創(chuàng)建的bean信息
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }

         else {  // session/request類型
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName, () -> {
                  beforePrototypeCreation(beanName);
                  try {
                     return createBean(beanName, mbd, args);  
                  }
                  finally {
                     afterPrototypeCreation(beanName);
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,
                     "Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                     ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   // Check if required type matches the type of the actual bean instance.
   if (requiredType != null && !requiredType.isInstance(bean)) {
      try {
         T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
         if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
         }
         return convertedBean;
      }
      catch (TypeMismatchException ex) {
         if (logger.isTraceEnabled()) {
            logger.trace("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}

在createBrean中涣脚,會(huì)實(shí)例化bean示辈,并且初始化,填充好bean的成員屬性遣蚀,詳細(xì)分析見(jiàn)《spring源碼分析6----bean字段or成員變量填充》矾麻,這篇已經(jīng)對(duì)bean的實(shí)例化做了詳細(xì)的分析。prototype的bean使用完以后芭梯,會(huì)由垃圾回收對(duì)它進(jìn)行處理险耀。


上面講的是getBean顯式獲取bean,下面講注入的時(shí)候玖喘,prototyp類型的bean是怎么處理的胰耗。要接著上面的createBean繼續(xù)分析,實(shí)例化以后就是成員的填充芒涡,這里就會(huì)用到注入了柴灯。

在前面分析bean實(shí)例化的時(shí)候已經(jīng)涉及到類初始化,成員的填充费尽,這里只是前面文章內(nèi)容的延伸赠群。createBean調(diào)用doCreateBean。而doCreateBean會(huì)調(diào)用populateBean旱幼,填充bean查描。

/**
 * Populate the bean instance in the given BeanWrapper with the property values
 * from the bean definition.
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param bw the BeanWrapper with bean instance
 */
@SuppressWarnings("deprecation")  // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   if (bw == null) { //實(shí)例為null
      if (mbd.hasPropertyValues()) {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
         // Skip property population phase for null instance.
         return;
      }
   }

   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {  //做一些預(yù)處理
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               return;
            }
         }
      }
   }

   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); //獲取屬性

   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs); //按名稱注入
      }
      // Add property values based on autowire by type if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs); //按類型注入,看類型吧,比較快
      }
      pvs = newPvs;
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               if (filteredPds == null) {
                  filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
               }
               pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvsToUse == null) {
                  return;
               }
            }
            pvs = pvsToUse;
         }
      }
   }
   if (needsDepCheck) {
      if (filteredPds == null) {
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }

   if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs); //填充在這里完成
   }
}

去看autowireByType

/**
 * Abstract method defining "autowire by type" (bean properties by type) behavior.
 * <p>This is like PicoContainer default, in which there must be exactly one bean
 * of the property type in the bean factory. This makes bean factories simple to
 * configure for small namespaces, but doesn't work as well as standard Spring
 * behavior for bigger applications.
 * @param beanName the name of the bean to autowire by type
 * @param mbd the merged bean definition to update through autowiring
 * @param bw the BeanWrapper from which we can obtain information about the bean
 * @param pvs the PropertyValues to register wired objects with
 */
protected void autowireByType(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

   TypeConverter converter = getCustomTypeConverter();
   if (converter == null) {
      converter = bw;
   }

   Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
   for (String propertyName : propertyNames) {
      try {
         PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
         // Don't try autowiring by type for type Object: never makes sense,
         // even if it technically is a unsatisfied, non-simple property.
         if (Object.class != pd.getPropertyType()) {
            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
            // Do not allow eager init for type matching in case of a prioritized post-processor.
            boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
            DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
            Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);  //查找屬性對(duì)應(yīng)的依賴
            if (autowiredArgument != null) {
               pvs.add(propertyName, autowiredArgument);
            }
            for (String autowiredBeanName : autowiredBeanNames) {
               registerDependentBean(autowiredBeanName, beanName);
               if (logger.isTraceEnabled()) {
                  logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
                        propertyName + "' to bean named '" + autowiredBeanName + "'");
               }
            }
            autowiredBeanNames.clear();
         }
      }
      catch (BeansException ex) {
         throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
      }
   }
}

這個(gè)方法當(dāng)中冬三,resolveDependency會(huì)調(diào)用doResolveDependency匀油。

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

   InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
   try {
      Object shortcut = descriptor.resolveShortcut(this);
      if (shortcut != null) {
         return shortcut;
      }

      Class<?> type = descriptor.getDependencyType();
      Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
      if (value != null) { //我們要看創(chuàng)建過(guò)程,這里跳過(guò)
         if (value instanceof String) {
            String strVal = resolveEmbeddedValue((String) value);
            BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                  getMergedBeanDefinition(beanName) : null);
            value = evaluateBeanDefinitionString(strVal, bd);
         }
         TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
         try {
            return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
         }
         catch (UnsupportedOperationException ex) {
            // A custom TypeConverter which does not support TypeDescriptor resolution...
            return (descriptor.getField() != null ?
                  converter.convertIfNecessary(value, type, descriptor.getField()) :
                  converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
         }
      }

      Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
      if (multipleBeans != null) {
         return multipleBeans;
      }

      Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
      if (matchingBeans.isEmpty()) {
         if (isRequired(descriptor)) {
            raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
         }
         return null;
      }

      String autowiredBeanName;
      Object instanceCandidate;

      if (matchingBeans.size() > 1) { //匹配到多個(gè)勾笆,這里不用看
         autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
         if (autowiredBeanName == null) {
            if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
               return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
            }
            else {
               // In case of an optional Collection/Map, silently ignore a non-unique case:
               // possibly it was meant to be an empty collection of multiple regular beans
               // (before 4.3 in particular when we didn't even look for collection beans).
               return null;
            }
         }
         instanceCandidate = matchingBeans.get(autowiredBeanName);
      }
      else { //精準(zhǔn)匹配到一個(gè)
         // We have exactly one match.
         Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
         autowiredBeanName = entry.getKey();
         instanceCandidate = entry.getValue();
      }

      if (autowiredBeanNames != null) {
         autowiredBeanNames.add(autowiredBeanName);
      }
      if (instanceCandidate instanceof Class) { //如果匹配到的是類敌蚜,這里我們要關(guān)注
         instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); //就是在這里實(shí)例化的
      }
      Object result = instanceCandidate;
      if (result instanceof NullBean) {
         if (isRequired(descriptor)) {
            raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
         }
         result = null;
      }
      if (!ClassUtils.isAssignableValue(type, result)) {
         throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
      }
      return result;
   }
   finally {
      ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
   }
}

在doresolveDependency方法中,對(duì)于prototype的bean窝爪,會(huì)去創(chuàng)建一個(gè)實(shí)例弛车,看一看descriptor.resolveCondidate

/**
 * Resolve the specified bean name, as a candidate result of the matching
 * algorithm for this dependency, to a bean instance from the given factory.
 * <p>The default implementation calls {@link BeanFactory#getBean(String)}.
 * Subclasses may provide additional arguments or other customizations.
 * @param beanName the bean name, as a candidate result for this dependency
 * @param requiredType the expected type of the bean (as an assertion)
 * @param beanFactory the associated factory
 * @return the bean instance (never {@code null})
 * @throws BeansException if the bean could not be obtained
 * @since 4.3.2
 * @see BeanFactory#getBean(String)
 */
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
      throws BeansException {

   return beanFactory.getBean(beanName); //這就是文章一開(kāi)始分析的方法
}

總結(jié)一下,populateBean填充bean實(shí)例的屬性蒲每,它先調(diào)用autowireByType獲取屬性的名稱纷跛,還有屬性要填充的值,在本篇中邀杏,這個(gè)值指的就是被prototype修飾的bean贫奠。這個(gè)值是通過(guò)getBean(name)來(lái)獲取的,而文章前面分析過(guò)getBean(name)對(duì)于prototype修飾的bean望蜡,是直接創(chuàng)建一個(gè)實(shí)例叮阅。從代碼來(lái)看,在自動(dòng)注入的情況下泣特,prototype修飾的bean總是會(huì)被重新創(chuàng)建浩姥。

寫(xiě)在最后:接單,有后臺(tái)活java/cpp/lua/go聯(lián)系shihuaping0918@163.com状您。不上班了也要有點(diǎn)收入才行勒叠。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市膏孟,隨后出現(xiàn)的幾起案子眯分,更是在濱河造成了極大的恐慌,老刑警劉巖柒桑,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弊决,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡魁淳,警方通過(guò)查閱死者的電腦和手機(jī)飘诗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)界逛,“玉大人昆稿,你說(shuō)我怎么就攤上這事∠荩” “怎么了溉潭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵净响,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我喳瓣,道長(zhǎng)馋贤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任畏陕,我火速辦了婚禮配乓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹭秋。我一直安慰自己扰付,他們只是感情好堤撵,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布仁讨。 她就那樣靜靜地躺著,像睡著了一般实昨。 火紅的嫁衣襯著肌膚如雪洞豁。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天荒给,我揣著相機(jī)與錄音丈挟,去河邊找鬼。 笑死志电,一個(gè)胖子當(dāng)著我的面吹牛曙咽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挑辆,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼例朱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了鱼蝉?” 一聲冷哼從身側(cè)響起洒嗤,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎魁亦,沒(méi)想到半個(gè)月后渔隶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡洁奈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年间唉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片利术。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡终吼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出氯哮,到底是詐尸還是另有隱情际跪,我是刑警寧澤商佛,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站姆打,受9級(jí)特大地震影響良姆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜幔戏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一玛追、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闲延,春花似錦痊剖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至合愈,卻和暖如春叮贩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背佛析。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工益老, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寸莫。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓捺萌,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親膘茎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子桃纯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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