Spring源碼分析之IOC

IOC(Inversion of Control),即控制反轉(zhuǎn),是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,可以用來(lái)減低代碼之間的耦合度。在Spring中,IOC意味著對(duì)象和資源的創(chuàng)建和獲取統(tǒng)一交給了容器,由容器控制對(duì)象的生命周期和對(duì)象間的依賴關(guān)系。

而DI(Dependency Injection),即依賴注入,是實(shí)現(xiàn)IOC的一種手段。DI意味著組件之間依賴關(guān)系由容器在運(yùn)行期決定,形象的說(shuō),即由容器動(dòng)態(tài)的將某個(gè)依賴關(guān)系注入到組件之中。

要理解Spring IOC的實(shí)現(xiàn),首先需要了解下面兩個(gè)接口:BeanFactory和ApplicationContext

1. BeanFactory

BeanFactory是Spring中的Bean工廠, 用于Spring中Bean的生命周期管理。它的主要接口如下:

public interface BeanFactory {
    /*
     * 四個(gè)不同形式的getBean方法,獲取實(shí)例
     */
    Object getBean(String name) throws BeansException;

    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    <T> T getBean(Class<T> requiredType) throws BeansException;

    Object getBean(String name, Object... args) throws BeansException;

    boolean containsBean(String name); // 是否存在

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 是否為單例

    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 是否為原型(多實(shí)例)

    boolean isTypeMatch(String name, Class<?> targetType)
            throws NoSuchBeanDefinitionException;// 名稱、類型是否匹配

    Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 獲取類型

    String[] getAliases(String name);// 根據(jù)實(shí)例的名字獲取實(shí)例的別名
    
    //......
}

2. ApplicationContext

ApplicationContext是BeanFactory的子接口,在擁有所有BeanFactory功能的基礎(chǔ)上,它還繼承了一些其他接口:


ApplicationContext.jpg

因此,ApplicationContext擁有一些高階功能,例如:

  • HierarchicalBeanFactory 是一個(gè)具有層級(jí)關(guān)系的 BeanFactory,擁有屬性 parentBeanFactory。ListableBeanFactory 實(shí)現(xiàn)了枚舉方法可以列舉出當(dāng)前 BeanFactory 中所有的 bean 對(duì)象而不必根據(jù) name 一個(gè)一個(gè)的獲取。
  • MessageSource接口提供國(guó)際化功能
  • ApplicationEventPublisher提供事件發(fā)布訂閱功能
  • ResourceLoader提供資源加載功能
  • EnvironmentCapable用于獲取 Environment 的功能

ApplicationContext常用實(shí)現(xiàn)類包括:ClassPathXMLApplicationContext, FileSystemXmlApplicationContext,AnnotationConfigApplicationContext和WebApplicationContext。

3. 容器入口

我們以ClassPathXmlApplicationContext為例,下面是其構(gòu)造函數(shù):

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

Spring首先讀取Config文件位置,然后調(diào)用refresh方法進(jìn)行BeanFactory的構(gòu)建。

4. 容器構(gòu)建流程

下面是AbstractApplicationContext中refresh方法的實(shí)現(xiàn):

public void refresh() throws BeansException, IllegalStateException {
  // refresh過(guò)程只能一個(gè)線程處理,不允許并發(fā)執(zhí)行
  synchronized (this.startupShutdownMonitor) {
    prepareRefresh();
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    prepareBeanFactory(beanFactory);
    try {
      postProcessBeanFactory(beanFactory);
      invokeBeanFactoryPostProcessors(beanFactory);
      registerBeanPostProcessors(beanFactory);
      initMessageSource();
      initApplicationEventMulticaster();
      onRefresh();
      registerListeners();
      finishBeanFactoryInitialization(beanFactory);
      finishRefresh();
    }
    catch (BeansException ex) {
      if (logger.isWarnEnabled()) {
        logger.warn("Exception encountered during context initialization - " +
            "cancelling refresh attempt: " + ex);
      }
      destroyBeans();
      cancelRefresh(ex);
      throw ex;
    }
    finally {
      resetCommonCaches();
    }
  }
}

主要的流程圖如下:


ApplicationContext refresh.png

4.1 prepareRefresh

執(zhí)行一些初始化操作,包括記錄當(dāng)前時(shí)間,初始化變量等。其源碼如下:

protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }

        // Initialize any placeholder property sources in the context environment
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
}

4.2 obtainFreshBeanFactory

創(chuàng)建一個(gè)BeanFactory。此方法會(huì)調(diào)用refreshBeanFactory方法,其源碼如下:

protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
}

從源碼上看,refreshBeanFactory方法的主要流程如下:

  1. 若已經(jīng)存在beanFactory,銷毀它
  2. 創(chuàng)建新的beanFactory(new DefaultListableBeanFactory(getInternalParentBeanFactory()))
  3. 通過(guò)customizeBeanFactory定制BeanFactory的屬性;
  4. 加載BeanDefinition到當(dāng)前BeanFactory中(對(duì)于ClassPathXmlApplicationContext來(lái)說(shuō),會(huì)調(diào)用XmlBeanDefinitionReader讀取所有的Bean定義,封裝為BeanDefinition注冊(cè)到BeanFactory中);

ApplicationContext實(shí)現(xiàn)了BeanFactory接口,其內(nèi)部是通過(guò)聚合一個(gè)DefaultListableBeanFactory來(lái)實(shí)現(xiàn)所有的BeanFactory功能的。

下面時(shí)BeanDefinition接口的主要定義:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    //單例作用域
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    //原型作用域
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    String getParentName();
    void setParentName(String parentName);

    String getBeanClassName();
    void setBeanClassName(String beanClassName);

    String getScope();
    void setScope(String scope);

    boolean isLazyInit();
    void setLazyInit(boolean lazyInit);

    boolean isPrimary();
    void setPrimary(boolean primary);

    boolean isSingleton();
    boolean isPrototype();
    //......
}

DefaultListableBeanFactory中維護(hù)了一個(gè)Map用于存儲(chǔ)所有的BeanDefinition:

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

另外,DefaultSingletonBeanRegistryDefaultListableBeanFactory的父類)中維護(hù)了一個(gè)Map用于存儲(chǔ)所有的Bean:

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

4.3 prepareBeanFactory

在BeanFactory已經(jīng)創(chuàng)建成功后,Spring會(huì)調(diào)用prepareBeanFactory(beanFactory)來(lái)向已經(jīng)創(chuàng)建的BeanFactory注冊(cè)一些特定的Bean,包括environment等:

   // 如果沒(méi)有定義 "environment" 這個(gè) bean,那么 Spring 會(huì) "手動(dòng)" 注冊(cè)一個(gè)
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   // 如果沒(méi)有定義 "systemProperties" 這個(gè) bean,那么 Spring 會(huì) "手動(dòng)" 注冊(cè)一個(gè)
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   // 如果沒(méi)有定義 "systemEnvironment" 這個(gè) bean,那么 Spring 會(huì) "手動(dòng)" 注冊(cè)一個(gè)
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }

另外,還會(huì)注冊(cè)一些BeanPostProcessor,包括ApplicationContextAwareProcessorApplicationListenerDetector等:

   // 添加一個(gè) BeanPostProcessor,這個(gè) processor 比較簡(jiǎn)單,
   // 實(shí)現(xiàn)了 Aware 接口的幾個(gè)特殊的 beans 在初始化的時(shí)候,這個(gè) processor 負(fù)責(zé)回調(diào)
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

   // 這個(gè) BeanPostProcessor 也很簡(jiǎn)單,在 bean 實(shí)例化后,如果是 ApplicationListener 的子類,
   // 那么將其添加到 listener 列表中,可以理解成:注冊(cè)事件監(jiān)聽器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

4.3 postProcessBeanFactory

在BeanFactory基本完成后,Spring調(diào)用postProcessBeanFactory(beanFactory)來(lái)進(jìn)行后續(xù)的針對(duì)BeanFactory的操作。AbstractApplicationContext中的默認(rèn)實(shí)現(xiàn)為空。而其子類AnnotationConfigEmbeddedWebApplicationContext對(duì)應(yīng)的postProcessBeanFactory方法則會(huì)掃描basePackage下的bean并注冊(cè)到BeanFactory中。

4.4 invokeBeanFactoryPostProcessors

在BeanFactory創(chuàng)建完畢后,Spring調(diào)用invokeBeanFactoryPostProcessors(beanFactory)來(lái)運(yùn)行所有已經(jīng)注冊(cè)的BeanFactoryPostProcessor,從而進(jìn)行修改BeanFactory或修改BeanFactory中已經(jīng)存在的BeanDefinition。

public interface BeanFactoryPostProcessor {

    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     * @param beanFactory the bean factory used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

常見的BeanFactoryPostProcessor包括ConfigurationClassPostProcessorPropertyPlaceholderConfigurer等。

ConfigurationClassPostProcessor用于讀取所有已經(jīng)注冊(cè)的Configuration類型的Bean,然后注入Configuration類中定義的Bean,最后判斷該Configuration是否擁有ComponentScan注解,如果擁有則掃描basePackage下的所有bean并注冊(cè)到BeanFactory中。

如果spring配置文件中包含了<context:annotation-config/> 或 <context:component-scan/>,spring則會(huì)自動(dòng)啟用ConfigurationClassPostProcessor

invokeBeanFactoryPostProcessors(beanFactory)方法內(nèi)部首先對(duì)所有的BeanFactoryPostProcessor進(jìn)行排序,然后依次調(diào)用。

4.5 registerBeanPostProcessors

registerBeanPostProcessors方法會(huì)對(duì)所有BeanFactory內(nèi)的BeanPostProcessor類型的Bean進(jìn)行排序,然后調(diào)用registerBeanPostProcessors注冊(cè)這些BeanPostProcessor,最終在createBean時(shí)會(huì)依次調(diào)用這些BeanPostProcessor來(lái)customize最終生成的Bean。BeanPostProcessorBeanFactoryPostProcessor的區(qū)別在于,BeanPostProcessor用于實(shí)例化bean后再customize bean,而BeanFactoryPostProcessor則用于BeanFactory創(chuàng)建完成后customize BeanFactory。

BeanPostProcessor接口如下:

public interface BeanPostProcessor {
    // inti方法調(diào)用之前的操作
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    // init方法調(diào)用之后的操作
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

BeanPostProcessor調(diào)用時(shí)bean已經(jīng)被實(shí)例化,并且所有該注入的屬性都已經(jīng)被注入,是一個(gè)完整的Bean。下面是postProcessBeforeInitializationpostProcessAfterInitialization的調(diào)用時(shí)間:

  1. 在Bean實(shí)例化完成后調(diào)用BeanPostProcessor.postProcessBeforeInitialization
  2. 如果Bean實(shí)現(xiàn)了InitializingBean接口,則調(diào)用InitializingBean.afterPropertiesSet方法
  3. 如果Bean中配置了init-method,則調(diào)用init-method
  4. 調(diào)用BeanPostProcessor.postProcessAfterInitialization

InitializingBean接口的定義如下:

public interface InitializingBean {

    /**
     * Invoked by a BeanFactory after it has set all bean properties supplied
     * (and satisfied BeanFactoryAware and ApplicationContextAware).
     * <p>This method allows the bean instance to perform initialization only
     * possible when all bean properties have been set and to throw an
     * exception in the event of misconfiguration.
     * @throws Exception in the event of misconfiguration (such
     * as failure to set an essential property) or if initialization fails.
     */
    void afterPropertiesSet() throws Exception;

}

常見的BeanPostProcessor包括ApplicationContextAwareProcessorApplicationListenerDetectorAutowiredAnnotationBeanPostProcessor等。

ApplicationContextAwareProcessor用于調(diào)用Bean的Aware的接口(包括ApplicationContextAware,MessageSourceAware,ApplicationEventPublisherAware等)。例如如果Bean實(shí)現(xiàn)了ApplicationContextAware接口,在Bean實(shí)例化結(jié)束后,會(huì)調(diào)用ApplicationContextAware接口的setApplicationContext(ApplicationContext applicationContext)方法來(lái)cutomize實(shí)例化后的Bean。

ApplicationListenerDetector用于如果Bean實(shí)現(xiàn)了ApplicationListener接口,那么它會(huì)將這個(gè)Bean加入ApplicationEventMulticaster的listener列表中。

AutowiredAnnotationBeanPostProcessor用于注入所有使用了@Autowired注解的屬性。

4.6 initMessageSource

MessageSource是Spring提供國(guó)際化的接口。ApplicationContext實(shí)現(xiàn)了MessageSource接口,其內(nèi)部是通過(guò)聚合一個(gè)MessageSource對(duì)象來(lái)實(shí)現(xiàn)的。initMessageSource方法主要是為了初始化ApplicationContext內(nèi)部的MessageSource對(duì)象。如果BeanFactory中存在一個(gè)MessageSource Bean,那么直接將這個(gè)Bean賦值給ApplicationContext內(nèi)部的MessageSource對(duì)象。如果沒(méi)有,則會(huì)構(gòu)造一個(gè)new DelegatingMessageSource()對(duì)象。

4.7 initApplicationEventMulticaster

initApplicationEventMulticaster顧名思義,是為了初始化ApplicationEventMulticaster。ApplicationContext實(shí)現(xiàn)了ApplicationEventPublisher接口,從而具備了事件發(fā)布功能。其內(nèi)部是通過(guò)聚合一個(gè)ApplicationEventMulticaster實(shí)現(xiàn)的。下面是初始化代碼:

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                        "': using default [" + this.applicationEventMulticaster + "]");
            }
        }
    }

initMessageSource方法類似,如果BeanFactory中存在一個(gè)名為applicationEventMulticaster的對(duì)象,則將其賦值給內(nèi)部的this.applicationEventMulticaster。否則,直接通過(guò)new SimpleApplicationEventMulticaster(beanFactory)實(shí)例化一個(gè)ApplicationEventMulticaster。之后ApplicationContext所有事件發(fā)布功能都會(huì)轉(zhuǎn)交給內(nèi)部的applicationEventMulticaster對(duì)象。

ApplicationEventMulticaster主要負(fù)責(zé)事件的發(fā)布和監(jiān)聽者的注冊(cè)。主要接口如下:

// 注冊(cè)監(jiān)聽者
void addApplicationListener(ApplicationListener<?> listener);
//發(fā)布事件
void multicastEvent(ApplicationEvent event);
//......

ApplicationEventMulticaster的實(shí)現(xiàn)類內(nèi)部擁有一個(gè)Set<ApplicationListener<?>> applicationListeners監(jiān)聽者集合。在掃描出所有實(shí)現(xiàn)了ApplicationListener接口的類后,通過(guò)以下方法創(chuàng)建一個(gè)ApplicationListener<?>對(duì)象,然后添加到Set<ApplicationListener<?>> applicationListeners監(jiān)聽者集合中。

public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
   return new ApplicationListenerMethodAdapter(beanName, type, method);
}

4.8 onRefresh

擴(kuò)展方法,由子類實(shí)現(xiàn)用于初始化其他的特殊Bean。AbstractApplicationContext默認(rèn)實(shí)現(xiàn)為空。

4.9 registerListeners

注冊(cè)事件監(jiān)聽器。將BeanFactory中存在的ApplicationListener類型的Bean注冊(cè)到ApplicationContext內(nèi)部的ApplicationEventMulticaster中。

4.10 finishBeanFactoryInitialization

通過(guò)調(diào)用beanFactory.preInstantiateSingletons()實(shí)例化所有非懶加載的單例Bean。beanFactory.preInstantiateSingletons()則會(huì)遍歷所有的Bean并調(diào)用getBean(beanName)方法。

下面是getBean(beanName)方法的流程:

  1. 首先通過(guò)getSingleton(beanName)從signleton緩存池中獲取Bean
  2. 如果獲取不到,則根據(jù)當(dāng)前的beanfactory獲取父一級(jí)的beanfactory,然后逐級(jí)遞歸的查找我們需要的bean
  3. 獲取仍然不到則根據(jù)final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName)拿到BeanDefinition,然后通過(guò)createBean(beanName, mbd, args)進(jìn)行Bean的創(chuàng)建。
  4. createBean(beanName, mbd, args)方法調(diào)用doCreateBean(beanName, mbdToUse, args)方法來(lái)創(chuàng)建Bean。
  5. doCreateBean(beanName, mbdToUse, args)方法主要分為四步:
    (1) instanceWrapper = createBeanInstance(beanName, mbd, args) 通過(guò)反射創(chuàng)建出一個(gè)Bean實(shí)例
    (2)applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName) 調(diào)用所有的MergedBeanDefinitionPostProcessor來(lái)customize創(chuàng)建出的Bean。
    (3) populateBean(beanName, mbd, instanceWrapper) 填充所有的屬性
    (4) exposedObject = initializeBean(beanName, exposedObject, mbd) 調(diào)用applyBeanPostProcessorsBeforeInitialization(即BeanPostProcessor.beforeInitialization),invokeInitMethods(即配置文件中配置的init-method)和applyBeanPostProcessorsAfterInitialization(即BeanPostProcessor.afterInitialization)

上文中我們提到的AutowiredAnnotationBeanPostProcessor是一種BeanPostProcessor(然而它的beforeInitialization和afterInitialization都為空),它還實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口。因此上述第(2)步會(huì)調(diào)用AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法,然而這個(gè)方法并不會(huì)直接向Bean中注入所有的@Autowired屬性。下面是這個(gè)方法的實(shí)現(xiàn):

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    if (beanType != null) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }
}

AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition的作用僅僅是緩存此Bean的所有@Autowired屬性信息。

在執(zhí)行第(3)步populateBean(beanName, mbd, instanceWrapper) 時(shí),會(huì)調(diào)用其AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues方法,從而完成了所有@Autowired屬性的注入:

@Override
    public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
        }
        catch (BeanCreationException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
        }
        return pvs;
    }

更多Bean初始化流程,請(qǐng)參考:https://www.shangyang.me/2017/04/01/spring-core-container-sourcecode-analysis-beans-instantiating-process/

4.11 finishRefresh

執(zhí)行refresh收尾工作。包括初始化LifecycleProcessor,發(fā)布ContextRefreshedEvent事件等。其源碼如下:

protected void finishRefresh() {
        // Clear context-level resource caches (such as ASM metadata from scanning).
        clearResourceCaches();

        // Initialize lifecycle processor for this context.
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();

        // Publish the final event.
        publishEvent(new ContextRefreshedEvent(this));

        // Participate in LiveBeansView MBean, if active.
        LiveBeansView.registerApplicationContext(this);
}

參考文章:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,477評(píng)論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,960評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,200評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,617評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,807評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,049評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,432評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,769評(píng)論 2 372

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