Spring源碼2:發(fā)布啟動(dòng)事件ApplicationStartingEvent

上篇回顧

上一篇初始化SpringApplication實(shí)例, 我們實(shí)例化了一個(gè)SpringApplication實(shí)例,整個(gè)流程共計(jì)4步

  1. 調(diào)用WebApplicationType.deduceFromClasspath方法, 獲取Web類型
  2. 通過getSpringFactoriesInstances()方法, 調(diào)用SpringFactoriesLoader.loadFactoryNames, 首先加載META-INF/spring.factories配置的類名到緩存中, 之后實(shí)例化了ApplicationContextInitializer的子類列表, 賦值給SpringApplication的initializers列表
  3. 通過getSpringFactoriesInstances()方法, 調(diào)用SpringFactoriesLoader.loadFactoryNames,從SpringFactoriesLoader的緩存中獲取并實(shí)例化ApplicationListener子類列表, 賦值SpringApplication的listeners列表
  4. 通過拋出一個(gè)RuntimeException, 遍歷其堆棧信息, 獲取到類名中包含main方法的類, 實(shí)例化這個(gè)類, 賦值給SpringApplication的mainApplicationClass對象

目錄

1. 發(fā)布啟動(dòng)事件ApplicationStartingEvent
????1.1 SpringApplicationRunListeners源碼
????1.2 EventPublishingRunListener源碼
????1.3 SimpleApplicationEventMulticaster源碼
2. 啟動(dòng)事件的監(jiān)聽器
????2.1 LoggingApplicationListener
????2.2 BackgroundPreinitializer
????2.3 DelegatingApplicationListener
????2.4 LiquibaseServiceLocatorApplicationListener
3. 總結(jié)

1. 發(fā)布啟動(dòng)事件ApplicationStartingEvent

調(diào)用getRunListeners()方法, 實(shí)例化一個(gè)SpringApplicationRunListeners對象, SpringApplicationRunListeners的構(gòu)造參數(shù)通過getSpringFactoriesInstances()方法獲得,這個(gè)方法在之前分析過了, 獲取的一個(gè)EventPublishingRunListener對象, 所以調(diào)用的是EventPublishingRunListener#starting()方法

public class SpringApplication {
    //run方法
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        
        //本文分析的重點(diǎn),發(fā)布啟動(dòng)事件ApplicationStartingEvent
        //獲取SpringApplicationRunListener的子類listener
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //執(zhí)行其starting()方法
        listeners.starting();
        ....
    }
    
    //獲取SpringApplicationRunListener的子類listener
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        
        //調(diào)用getSpringFactoriesInstances方法
        //獲取SpringApplicationRunListener的子類
        //子類只有一個(gè),EventPublishingRunListener
        //實(shí)例化了一個(gè)SpringApplicationRunListeners對象
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }
}
1.1 SpringApplicationRunListeners源碼

SpringApplicationRunListeners是一個(gè)比較重要的類, 之后的代碼會(huì)經(jīng)常調(diào)用這個(gè)方法, 內(nèi)部封裝了一個(gè)SpringApplicationRunListener的list, 方便以后擴(kuò)展, 目前只有一個(gè)EventPublishingRunListener實(shí)例, 所以spring的事件都是由EventPublishingRunListener發(fā)布的

//SpringApplicationRunListeners部分源碼
class SpringApplicationRunListeners {

    private final Log log;

    //SpringApplicationRunListener的子類對象列表
    //listener列表擴(kuò)展點(diǎn)
    private final List<SpringApplicationRunListener> listeners;

    SpringApplicationRunListeners(Log log,
            Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList<>(listeners);
    }

    //發(fā)布啟動(dòng)事件
    public void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            //目前調(diào)用EventPublishingRunListener#starting方法
            listener.starting();
        }
    }
    
    //其他事件都是相同的代碼
    //....
}
1.2 EventPublishingRunListener源碼

EventPublishingRunListener是springboot的事件廣播器, 內(nèi)部封裝了一個(gè)SimpleApplicationEventMulticaster對象, 用來發(fā)布springboot加載過程中的各個(gè)事件

  • 事件源SpringApplication對象
  • 事件SpringApplicationEvent對象
  • 事件發(fā)布器是EventPublishingRunListener, 正在的事件發(fā)布器是其內(nèi)部SimpleApplicationEventMulticaster成員變量
  • 事件監(jiān)聽器SpringApplication維護(hù)的listeners, 調(diào)用AbstractApplicationEventMulticaster#getApplicationListeners(ApplicationEvent, ResolvableType)篩選出支持ApplicationEvent的listeners
//EventPublishingRunListener部分源碼
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

    //SpringApplication對象
    private final SpringApplication application;

    //命令函參數(shù)
    private final String[] args;

    //事件廣播器
    private final SimpleApplicationEventMulticaster initialMulticaster;

    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        // 通過application.getListeners(),獲取到Listener列表
        // ConfigFileApplicationListener
        // AnsiOutputApplicationListener
        // LoggingApplicationListener
        // ClasspathLoggingApplicationListener
        // BackgroundPreinitializer
        // DelegatingApplicationListener
        // ParentContextCloserApplicationListener
        // ClearCachesApplicationListener
        // FileEncodingApplicationListener
        // LiquibaseServiceLocatorApplicationListener
        for (ApplicationListener<?> listener : application.getListeners()) {
            //將listener添加到事件廣播器initialMulticaster
            this.initialMulticaster.addApplicationListener(listener);
        }
    }
    @Override
    public void starting() {
        // 廣播器廣播ApplicationStartingEvent事件
        this.initialMulticaster.multicastEvent(
                new ApplicationStartingEvent(this.application, this.args));
    }
    
    //其他事件發(fā)布都是相同的代碼
    //...
}

1.3 SimpleApplicationEventMulticaster源碼

springboot默認(rèn)事件廣播器, 有三個(gè)重要方法, 用于發(fā)布spring啟動(dòng)過程中的各個(gè)事件

  • addApplicationListener() 添加監(jiān)聽器listener
  • multicastEvent() 廣播spring事件
  • invokeListener() 實(shí)現(xiàn)每個(gè)listener的onApplicationEvent()方法
父類AbstractApplicationEventMulticaster

封裝了四個(gè)重要方法:

  • addApplicationListener添加listener
  • addApplicationListenerBean添加注入的listener bean名稱
  • removeApplicationListener刪除listener
  • removeApplicationListenerBean刪除注入的listener bean名稱
  • getApplicationListeners()先從緩存retrieverCache獲取listener,如果緩存不存在, 封裝數(shù)據(jù)放入緩存中, 增刪listener的時(shí)候, 緩存retrieverCache會(huì)被清空
//抽象事件廣播器
public abstract class AbstractApplicationEventMulticaster
        implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
    
    //監(jiān)聽器遍歷器
    //成員變量applicationListeners Set維護(hù)了application中包含的listeners,
    //成員變量applicationListenerBeans Set維護(hù)了注入的listener bean名稱
    private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);

    //調(diào)用getApplicationListeners()方法之后
    //緩存spring事件以及對應(yīng)的listener列表
    final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);

    private Object retrievalMutex = this.defaultRetriever;

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        synchronized (this.retrievalMutex) {
            //監(jiān)聽器已經(jīng)被加載過,
            //先執(zhí)行刪除操作,防止重復(fù)執(zhí)行
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }
            this.defaultRetriever.applicationListeners.add(listener);
            //清空緩存
            this.retrieverCache.clear();
        }
    }
    
    /**
     * 獲取支持監(jiān)聽event的listener
     * 這里使用了單例模式
     */
    protected Collection<ApplicationListener<?>> getApplicationListeners(
            ApplicationEvent event, ResolvableType eventType) {

        Object source = event.getSource();
        Class<?> sourceType = (source != null ? source.getClass() : null);
        ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

        //嘗試從ConcurrentHashMap緩存中取出listener列表
        ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
        if (retriever != null) {
            return retriever.getApplicationListeners();
        }

        if (this.beanClassLoader == null ||
                (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                        (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            //雙重檢查鎖定
            //當(dāng)多線程訪問的時(shí)候,
            //之前retriever多個(gè)線程否返回null,
            //此時(shí)鎖住this.retrievalMutex
            //防止多次實(shí)例化
            synchronized (this.retrievalMutex) {
                //再嘗試從cache中獲取
                retriever = this.retrieverCache.get(cacheKey);
                if (retriever != null) {
                    return retriever.getApplicationListeners();
                }
                //生成Key和Value放入緩存中
                retriever = new ListenerRetriever(true);
                Collection<ApplicationListener<?>> listeners =
                        retrieveApplicationListeners(eventType, sourceType, retriever);
                this.retrieverCache.put(cacheKey, retriever);
                return listeners;
            }
        }
        else {
            //沒有緩存ListenerRetriever,那么就不需要同步
            return retrieveApplicationListeners(eventType, sourceType, null);
        }
    }
    
    //retrieveApplicationListeners方法中
    //調(diào)用了supportsEvent方法
    //supportsEvent使用了適配器模式
    protected boolean supportsEvent(
            ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
        GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
                (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
        return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
    }
}
SimpleApplicationEventMulticaster

廣播事件, 然后實(shí)現(xiàn)每個(gè)listener的onApplicationEvent()方法

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    @Nullable
    private Executor taskExecutor;

    @Nullable
    private ErrorHandler errorHandler;

    /**
     * 構(gòu)造函數(shù)
     * taskExecutor和errorHandler都是null
     */
    public SimpleApplicationEventMulticaster() {
    }
    
    /**
     * 廣播事件
     * @param event 事件
     * @param eventType 事件類型
     */
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //調(diào)用父類getApplicationListeners方法
        //遍歷所有支持ApplicationStartingEvent事件的監(jiān)聽器
        //LoggingApplicationListener
        //BackgroundPreinitializer
        //DelegatingApplicationListener
        //LiquibaseServiceLocatorApplicationListener
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            //此時(shí)的executor為null
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                //調(diào)用listener
                invokeListener(listener, event);
            }
        }
    }
    
    /**
     * 具體調(diào)用監(jiān)聽器的方法
     * @param listener 監(jiān)聽器
     * @param event 事件
     */
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            //調(diào)用listener的onApplicationEvent方法
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                Log logger = LogFactory.getLog(getClass());
                if (logger.isDebugEnabled()) {
                    logger.debug("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }
}

2. 啟動(dòng)事件的監(jiān)聽器

對Spring啟動(dòng)事件ApplicationStartingEvent感興趣的Listener:

  • LoggingApplicationListener 日志監(jiān)聽器,配置日志
  • BackgroundPreinitializer 后臺(tái)初始化器, 多線程加載耗時(shí)任務(wù)
  • DelegatingApplicationListener 代理監(jiān)聽器, 繼續(xù)發(fā)布事件
  • LiquibaseServiceLocatorApplicationListener 將liquibas替換為可以和spring配合工作的版本
2.1 LoggingApplicationListener部分代碼

獲取當(dāng)前應(yīng)用使用的日志系統(tǒng), 初始化loggingSystem, 調(diào)用loggingSystem的beforeInitialize方法, 開啟日志的準(zhǔn)備工作

public class LoggingApplicationListener implements GenericApplicationListener {
    //處理starting事件
    if (event instanceof ApplicationStartingEvent) {
            onApplicationStartingEvent((ApplicationStartingEvent) event);
        }
    }
    
    //日志系統(tǒng)準(zhǔn)備工作
    private void onApplicationStartingEvent(ApplicationStartingEvent event) {
        //1.獲取模塊使用的日志系統(tǒng)
        this.loggingSystem = LoggingSystem
                .get(event.getSpringApplication().getClassLoader());
        //2.日志系統(tǒng)準(zhǔn)備工作
        //調(diào)用的是LogbackLoggingSystem#beforeInitialize
        this.loggingSystem.beforeInitialize();
    }
}
LoggingSystem

spring支持logback, Log4j, JDK logging, 有兩個(gè)重要方法

  • get() 獲取應(yīng)用使用的日志系統(tǒng)
  • beforeInitialize()獲取

springboot默認(rèn)使用logback, 也就是LogbackLoggingSystem

/**
 *日志系統(tǒng)的父類
 */
public abstract class LoggingSystem {

    public static final String SYSTEM_PROPERTY = LoggingSystem.class.getName();
    
    //Spring支持的幾種日志系統(tǒng)
    private static final Map<String, String> SYSTEMS;

    static {
        Map<String, String> systems = new LinkedHashMap<>();
        //1.logback
        systems.put("ch.qos.logback.core.Appender",
                "org.springframework.boot.logging.logback.LogbackLoggingSystem");
        //2.Log4j
        systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory",
                "org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");
        //3.JDK logging
        systems.put("java.util.logging.LogManager",
                "org.springframework.boot.logging.java.JavaLoggingSystem");
        SYSTEMS = Collections.unmodifiableMap(systems);
    }

    /**
     * 判斷并返回模塊使用的日志系統(tǒng)
     * 我們應(yīng)用使用的是logback
     * @param classLoader 加載SpringApplication的classloader
     */
    public static LoggingSystem get(ClassLoader classLoader) {
        String loggingSystem = System.getProperty(SYSTEM_PROPERTY);
        if (StringUtils.hasLength(loggingSystem)) {
            if (NONE.equals(loggingSystem)) {
                return new NoOpLoggingSystem();
            }
            return get(classLoader, loggingSystem);
        }
        //使用加載SpringApplication的classloader去加載支持的日志
        //如果能加載一個(gè)或者多個(gè),返回第一個(gè)
        //否則就拋出異常
        return SYSTEMS.entrySet().stream()
                .filter((entry) -> ClassUtils.isPresent(entry.getKey(), classLoader))
                .map((entry) -> get(classLoader, entry.getValue())).findFirst()
                .orElseThrow(() -> new IllegalStateException(
                        "No suitable logging system located"));
    }
}

/**
 * logback日志系統(tǒng)
 * 繼承了Sfl4j日志系統(tǒng)
 */
public class LogbackLoggingSystem extends Slf4JLoggingSystem {
    @Override
    public void beforeInitialize() {
        //獲取LoggerContext
        LoggerContext loggerContext = getLoggerContext();
        //如果logger已經(jīng)被初始化,name直接返回
        if (isAlreadyInitialized(loggerContext)) {
            return;
        }
        //調(diào)用父類的beforeInitialize方法
        //默認(rèn)使用debug模式
        super.beforeInitialize();
        loggerContext.getTurboFilterList().add(FILTER);
    }
}

2.2 BackgroundPreinitializer

Spring會(huì)在項(xiàng)目啟動(dòng)的時(shí)候,默認(rèn)開啟線程加載一些耗時(shí)的任務(wù),這樣可以加快啟動(dòng)速度

@Order(LoggingApplicationListener.DEFAULT_ORDER + 1)
public class BackgroundPreinitializer
        implements ApplicationListener<SpringApplicationEvent> {
        
    //系統(tǒng)屬性用來配置是夠需要忽略預(yù)加載
    public static final String IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME = "spring.backgroundpreinitializer.ignore";
    
    //預(yù)加載是否執(zhí)行,啟動(dòng)原子布爾類型,默認(rèn)為false
    private static final AtomicBoolean preinitializationStarted = new AtomicBoolean(
            false);

    //同步工具
    private static final CountDownLatch preinitializationComplete = new CountDownLatch(1);
}
2.3 DelegatingApplicationListener

擴(kuò)展點(diǎn), 可以繼續(xù)廣播事件, 查找屬性context.listener.classes對應(yīng)的listener名稱列表, 實(shí)例化代理監(jiān)聽器, 繼續(xù)廣播事件, 當(dāng)前應(yīng)用中沒有做任何操作

public class DelegatingApplicationListener
        implements ApplicationListener<ApplicationEvent>, Ordered {
        
    private static final String PROPERTY_NAME = "context.listener.classes";
            
    //默認(rèn)為null
    private SimpleApplicationEventMulticaster multicaster;

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            //監(jiān)聽到EnvironmentPreparedEvent事件
            List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
                    ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
            if (delegates.isEmpty()) {
                return;
            }
            this.multicaster = new SimpleApplicationEventMulticaster();
            for (ApplicationListener<ApplicationEvent> listener : delegates) {
                this.multicaster.addApplicationListener(listener);
            }
        }
        if (this.multicaster != null) {
            //再次發(fā)送事件
            this.multicaster.multicastEvent(event);
        }
    }
    
    //生成并返回Listener
    private List<ApplicationListener<ApplicationEvent>> getListeners(
            ConfigurableEnvironment environment) {
        if (environment == null) {
            return Collections.emptyList();
        }
        //獲取屬性名稱對應(yīng)的事件監(jiān)聽器名稱
        String classNames = environment.getProperty(PROPERTY_NAME);
        List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<>();
        if (StringUtils.hasLength(classNames)) {
            for (String className : StringUtils.commaDelimitedListToSet(classNames)) {
                try {
                    //反射生成對象
                    //放入監(jiān)聽器列表中
                    Class<?> clazz = ClassUtils.forName(className,
                            ClassUtils.getDefaultClassLoader());
                    Assert.isAssignable(ApplicationListener.class, clazz, "class ["
                            + className + "] must implement ApplicationListener");
                    listeners.add((ApplicationListener<ApplicationEvent>) BeanUtils
                            .instantiateClass(clazz));
                }
                catch (Exception ex) {
                    throw new ApplicationContextException(
                            "Failed to load context listener class [" + className + "]",
                            ex);
                }
            }
        }
        AnnotationAwareOrderComparator.sort(listeners);
        return listeners;
    }
}
2.4 LiquibaseServiceLocatorApplicationListener
public class LiquibaseServiceLocatorApplicationListener
        implements ApplicationListener<ApplicationStartingEvent> {
    if (ClassUtils.isPresent("liquibase.servicelocator.CustomResolverServiceLocator",
            event.getSpringApplication().getClassLoader())) {
        //將liquibas替換為 可以和spring配合工作的版本
        new LiquibasePresent().replaceServiceLocator();
    }
}

3. 總結(jié)

  1. 首先調(diào)用getRunListeners()方法, 獲得一個(gè)SpringApplicationRunListeners對象,
    • SpringApplicationRunListeners的成員變量listeners是通過getSpringFactoriesInstances()方法獲取的SpringApplicationRunListener子類列表
    • 當(dāng)前只能獲取EventPublishingRunListener,
  2. 調(diào)用SpringApplicationRunListeners對象的starting()方法, 發(fā)布SpringApplication啟動(dòng)事件
    • 內(nèi)部EventPublishingRunListener#starting()方法
    • 最終調(diào)用SimpleApplicationEventMulticaster#multicastEvent()方法
    • 發(fā)布了ApplicationStartingEvent事件, 最后執(zhí)行每個(gè)監(jiān)聽器的onApplicationEvent方法
  3. 對ApplicationStartingEvent事件感興趣的監(jiān)聽器
    • LoggingApplicationListener 日志監(jiān)聽器,配置日志
    • BackgroundPreinitializer 后臺(tái)初始化器, 多線程加載耗時(shí)任務(wù)
    • DelegatingApplicationListener 代理監(jiān)聽器, 繼續(xù)發(fā)布事件
    • LiquibaseServiceLocatorApplicationListener 將liquibas替換為可以和spring配合工作的版本

下一篇

我們將會(huì)在下一篇封裝命令行參數(shù)DefaultApplicationArguments, 繼續(xù)研究springboot的啟動(dòng)流程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子采桃,更是在濱河造成了極大的恐慌靖诗,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锭魔,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)困乒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贰谣,“玉大人娜搂,你說我怎么就攤上這事≈ǜВ” “怎么了百宇?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秘豹。 經(jīng)常有香客問我携御,道長,這世上最難降的妖魔是什么既绕? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任啄刹,我火速辦了婚禮,結(jié)果婚禮上凄贩,老公的妹妹穿的比我還像新娘誓军。我一直安慰自己,他們只是感情好疲扎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布昵时。 她就那樣靜靜地躺著,像睡著了一般评肆。 火紅的嫁衣襯著肌膚如雪债查。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天瓜挽,我揣著相機(jī)與錄音盹廷,去河邊找鬼。 笑死久橙,一個(gè)胖子當(dāng)著我的面吹牛俄占,可吹牛的內(nèi)容都是我干的管怠。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼缸榄,長吁一口氣:“原來是場噩夢啊……” “哼渤弛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起甚带,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤她肯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后鹰贵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晴氨,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年碉输,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了籽前。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡敷钾,死狀恐怖枝哄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阻荒,我是刑警寧澤挠锥,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站财松,受9級特大地震影響瘪贱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辆毡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一菜秦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舶掖,春花似錦球昨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鲫售,卻和暖如春共螺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背情竹。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工藐不, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓雏蛮,卻偏偏與公主長得像涎嚼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子挑秉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評論 2 350