深入剖析Spring boot自動裝配原理二(@Import)

前言

關于@Import注解的使用无拗,在Spring源碼中隨處可見,其作用大家基本也都知道遣总,無非就是注入指定的Bean到Spring IOC容器管理昌抠,只能作用用于類上患朱,其用法分三種:普通的類直接注入、實現(xiàn)了ImportSelector接口的類炊苫、實現(xiàn)了ImportBeanDefinitionRegistrar接口的類麦乞,那么Spring具體是如何實現(xiàn)的?這三種方式又有何不同劝评?一起跟進源碼一探究竟姐直,徹底了解Import的實現(xiàn)。

源碼追蹤(Spring版本:5.3.6-SNAPSHOT

眾所周知Spring需要先初始化上下文容器蒋畜,Spring上下文容器針對不同的場景設計了較多類型声畏,不過都大同小異,這里拿其中的AnnotationConfigApplicationContext進行講解姻成,如果需要進一步了解Spring的每一個容器或者Spring的更多源碼細節(jié)插龄,可關注我,我會在后面的章節(jié)中逐步揭開Spring源碼迷霧科展。

您的認可是我前進的動力均牢,如果您覺得可以請關注我并轉發(fā)文章,謝謝2哦谩E枪颉!

AnnotationConfigApplicationContext(AbstractApplicationContext)

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {

? // 注解配置上下文初始化

? this();

? // 將配置組件(AppConfig)注冊到AnnotationConfigApplicationContext上下文對象的beanFactory中(即將bean信息放入beanDefinitionMap中)

? register(componentClasses);

? // 刷新注冊到AnnotationConfigApplicationContext上下文對象的相關屬性

? refresh();

}

@Override

// AbstractApplicationContext公共方法

public void refresh() throws BeansException, IllegalStateException {

? synchronized (this.startupShutdownMonitor) {

? ? ? StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

? ? ? // Prepare this context for refreshing.

? ? ? prepareRefresh();

? ? ? // 刷新AnnotationConfigApplicationContext上下文對象的BeanFactory并返回BeanFactory對象

? ? ? ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

? ? ? // Prepare the bean factory for use in this context.

? ? ? prepareBeanFactory(beanFactory);

? ? ? try {

? ? ? ? // Allows post-processing of the bean factory in context subclasses.

? ? ? ? postProcessBeanFactory(beanFactory);

? ? ? ? StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

? ? ? ? // 實例化并調(diào)用所有已注冊的BeanFactoryPostProcessor的Bean到Spring容器中.

? ? ? ? invokeBeanFactoryPostProcessors(beanFactory);

? ? ......

? ? ? ? // 實例化所有BeanFactory中非延遲加載的Bean.

? ? ? ? finishBeanFactoryInitialization(beanFactory);

? ? ? ? // Last step: publish corresponding event.

? ? ? ? finishRefresh();

? ? ? }

? ? ......

}

PostProcessorRegistrationDelegate

public static void invokeBeanFactoryPostProcessors(

? ? ? ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

? ......

? ? ? // Do not initialize FactoryBeans here: We need to leave all regular beans

? ? ? // uninitialized to let the bean factory post-processors apply to them!

? ? ? // Separate between BeanDefinitionRegistryPostProcessors that implement

? ? ? // PriorityOrdered, Ordered, and the rest.

? ? ? List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

? ? ? // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.

? ? ? // 獲取BeanDefinitionRegistryPostProcessor類型的bean名稱,注意這里獲取到了名字為

? ? ? // org.springframework.context.annotation.internalConfigurationAnnotationProcessor的bean

? ? ? // (這個bean不是直接存在的琅攘,在AnnotationConfigUtils類中可查到其對應的Ben為ConfigurationClassPostProcessor)

? ? ? String[] postProcessorNames =

? ? ? ? ? ? beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

? ? ? for (String ppName : postProcessorNames) {

? ? ? ? if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {

? ? ? ? ? ? // beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)獲取到ConfigurationClassPostProcessor

? ? ? ? ? ? // 將ConfigurationClassPostProcessor添加到當前注冊Bean的處理對象集合

? ? ? ? ? ? currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

? ? ? ? ? ? processedBeans.add(ppName);

? ? ? ? }

? ? ? }

? ? ? // 將BeanDefinitionRegistryPostProcessor排序

? ? ? sortPostProcessors(currentRegistryProcessors, beanFactory);

? ? ? // 將BeanDefinitionRegistryPostProcessor稍后注冊到BeanFactory

? ? ? registryProcessors.addAll(currentRegistryProcessors);

? ? ? //

? ? ? invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());

? ? ? currentRegistryProcessors.clear();

? ? ? ......

}

通過調(diào)用PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors方法循環(huán)執(zhí)行所有BeanDefinitionRegistryPostProcessor垮庐,將相關Bean注入BeanFacotry。這里通過調(diào)用ConfigurationClassPostProcessor 處理所有@Configuration配置類坞琴,其通過核心方法processConfigBeanDefinitions來處理相關Bean的注入哨查。

ConfigurationClassPostProcessor

@Override

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

? // 生成處理ID

? int factoryId = System.identityHashCode(beanFactory);

? // 判斷后置處理器在registriesPostProcessed和factoriesPostProcessed中有沒有被調(diào)用過

? if (this.factoriesPostProcessed.contains(factoryId)) {

? ? ? throw new IllegalStateException(

? ? ? ? ? ? "postProcessBeanFactory already called on this post-processor against " + beanFactory);

? }

? // 調(diào)用前保存factoryId,防止被重復調(diào)用

? this.factoriesPostProcessed.add(factoryId);

? if (!this.registriesPostProcessed.contains(factoryId)) {

? ? ? // 注入標有@configuration的Bean里面需要注入的類(如:@Import注解)

? ? ? processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);

? }

? enhanceConfigurationClasses(beanFactory);

? beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));

}

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

? // 需要處理的候選@configuration類

? List<BeanDefinitionHolder> configCandidates = new ArrayList<>();

? // 獲取BeanFactory中注入的所有beanDefinitionNames

? String[] candidateNames = registry.getBeanDefinitionNames();

? for (String beanName : candidateNames) {

? ? ? BeanDefinition beanDef = registry.getBeanDefinition(beanName);

? ? ? // 檢查當前Bean是否已當作配置類處理過

? ? ? if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {

? ? ? ? if (logger.isDebugEnabled()) {

? ? ? ? ? ? logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);

? ? ? ? }

? ? ? }

? ? ? // 檢查當前Bean是否是配置類,如果是則添加到configCandidates中剧辐,后面進行處理

? ? ? else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {

? ? ? ? configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));

? ? ? }

? }

? // Return immediately if no @Configuration classes were found

? if (configCandidates.isEmpty()) {

? ? ? return;

? }

? ......

? // 準備解析 @Configuration 標注的類寒亥,構建解析對象

? ConfigurationClassParser parser = new ConfigurationClassParser(

? ? ? ? this.metadataReaderFactory, this.problemReporter, this.environment,

? ? ? ? this.resourceLoader, this.componentScanBeanNameGenerator, registry);

? // 配置Bean去重

? Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);

? // 存儲已解析過的配置類

? Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());

? // 循環(huán)解析

? do {

? ? ? StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");

? ? ? // 解析所有@Configuration標記Bean邮府,并將解析的Bean信息存入ConfigurationClassParser的configurationClasses集合中

? ? ? parser.parse(candidates);

? ? ? parser.validate();

? ? ? Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());

? ? ? configClasses.removeAll(alreadyParsed);

? ? ? // Read the model and create bean definitions based on its content

? ? ? if (this.reader == null) {

? ? ? ? this.reader = new ConfigurationClassBeanDefinitionReader(

? ? ? ? ? ? ? registry, this.sourceExtractor, this.resourceLoader, this.environment,

? ? ? ? ? ? ? this.importBeanNameGenerator, parser.getImportRegistry());

? ? ? }

? ? ? // 初始化所有配置類中的Bean(包含處理ImportBeanDefinitionRegistrars類),

? ? ? // 并將其放入Spring容器中(BeanFactory的beanDefinitionMap)

? ? ? this.reader.loadBeanDefinitions(configClasses);

? ? ? alreadyParsed.addAll(configClasses);

? ? ? processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

? ? ? candidates.clear();

? ? ? ......

? }

? while (!candidates.isEmpty());

? ......

}

通過調(diào)用ConfigurationClassParser#parse對@Configuration類進行解析溉奕。

ConfigurationClassParser

public void parse(Set<BeanDefinitionHolder> configCandidates) {

? for (BeanDefinitionHolder holder : configCandidates) {

? ? ? BeanDefinition bd = holder.getBeanDefinition();

? ? ? try {

? ? ? ? if (bd instanceof AnnotatedBeanDefinition) {

? ? ? ? ? ? // Configuration類為AnnotatedBean

? ? ? ? ? ? parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());

? ? ? ? }

? ? ? ? else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {

? ? ? ? ? ? parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());

? ? ? ? }

? ? ? ? else {

? ? ? ? ? ? parse(bd.getBeanClassName(), holder.getBeanName());

? ? ? ? }

? ? ? }

? ? ? ......

? }

? this.deferredImportSelectorHandler.process();

}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {

? processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);

}

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {

? // 判斷是否需要跳過該配置類的解析(例如配置了@Conditional注解)

? if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {

? ? ? return;

? }

? // 標識該配置類是否解析過

? ConfigurationClass existingClass = this.configurationClasses.get(configClass);

? ......

? // Recursively process the configuration class and its superclass hierarchy.

? // 將配置類轉為SourceClass類

? SourceClass sourceClass = asSourceClass(configClass, filter);

? // 從當前配置類configClass開始向上沿著類繼承結構逐層執(zhí)行doProcessConfigurationClass,

// 直到遇到的父類是由Java提供的類結束循環(huán)

? do {

? ? ? sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);

? }

? while (sourceClass != null);

? this.configurationClasses.put(configClass, configClass);

}

@Nullable

protected final SourceClass doProcessConfigurationClass(

? ? ? ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)

? ? ? throws IOException {

? ? // Component注解存在繼承關系挟纱,遞歸處理嵌套類

? if (configClass.getMetadata().isAnnotated(Component.class.getName())) {

? ? ? // Recursively process any member (nested) classes first

? ? ? processMemberClasses(configClass, sourceClass, filter);

? }

? ......

? // 重點來了,在這里處理Import注解

? processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

? ......

? // Process superclass, if any

? if (sourceClass.getMetadata().hasSuperClass()) {

? ? ? String superclass = sourceClass.getMetadata().getSuperClassName();

? ? ? if (superclass != null && !superclass.startsWith("java") &&

? ? ? ? ? ? !this.knownSuperclasses.containsKey(superclass)) {

? ? ? ? this.knownSuperclasses.put(superclass, configClass);

? ? ? ? // Superclass found, return its annotation metadata and recurse

? ? ? ? return sourceClass.getSuperClass();

? ? ? }

? }

? // No superclass -> processing is complete

? return null;

}

/**

? * 處理配置類上搜集到的@Import注解

? * @Param configuClass 配置類

? * @Param currentSourceClass 當前源碼類

? * @Param importCandidates 所有的@Import注解的value

? * @Param exclusionFilter 需要排除的類

? * @Param checkForCircularImports 是否檢查循環(huán)導入

? **/

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,

? ? ? Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,

? ? ? boolean checkForCircularImports) {

? if (importCandidates.isEmpty()) {

? ? ? return;

? }

? if (checkForCircularImports && isChainedImportOnStack(configClass)) {

? ? ? this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));

? }

? else {

? ? ? // 開始處理配置類configClass上@Import所有的importCandidates

? ? ? this.importStack.push(configClass);

? ? ? try {

? ? ? ? ? // 循環(huán)處理每一個@Import,每個@Import可能導入三種類型的類 :

? ? ? ? ? // 1. ImportSelector

? ? ? ? ? // 2. ImportBeanDefinitionRegistrar

? ? ? ? ? // 3. 其他類型腐宋,都當作配置類處理,也就是相當于使用了注解@Configuration的配置類

? ? ? ? // 下面的for循環(huán)中對這三種情況執(zhí)行了不同的處理邏輯

? ? ? ? for (SourceClass candidate : importCandidates) {

? ? ? ? ? ? // 處理ImportSelector類(Spring Boot的自動裝配采用的是這種方式)

? ? ? ? ? ? if (candidate.isAssignable(ImportSelector.class)) {

? ? ? ? ? ? ? // 加載對應的ImportSelector實現(xiàn)類

? ? ? ? ? ? ? Class<?> candidateClass = candidate.loadClass();

? ? ? ? ? ? ? // 實例化對應的實現(xiàn)ImportSelector的類

? ? ? ? ? ? ? ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,

? ? ? ? ? ? ? ? ? ? this.environment, this.resourceLoader, this.registry);

? ? ? ? ? ? ? // 獲取ImportSelector類中需要排除的實例化的類

? ? ? ? ? ? ? Predicate<String> selectorFilter = selector.getExclusionFilter();

? ? ? ? ? ? ? if (selectorFilter != null) {

? ? ? ? ? ? ? ? ? exclusionFilter = exclusionFilter.or(selectorFilter);

? ? ? ? ? ? ? }

? ? ? ? ? ? ? // 后置處理類交由后置處理器進行處理檀轨,本類涵蓋代碼的第18行代碼處理(this.deferredImportSelectorHandler.process();)

? ? ? ? ? ? ? if (selector instanceof DeferredImportSelector) {

? ? ? ? ? ? ? ? ? this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);

? ? ? ? ? ? ? }

? ? ? ? ? ? ? else {

? ? ? ? ? ? ? ? ? // 調(diào)用實現(xiàn)ImportSelector的類的selectImports胸竞,獲取需要實例化類的className

? ? ? ? ? ? ? ? ? String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());

? ? ? ? ? ? ? ? ? // 從當前ImportSelector需要實例化的類開始向上沿著類繼承結構逐層執(zhí)行將className加入到BeanFactory的beanDefinitionMap中(要排除的類除外),

? ? ? ? ? ? ? ? // 直到遇到的父類是由Java提供的類結束循環(huán)

? ? ? ? ? ? ? ? ? Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);

? ? ? ? ? ? ? ? ? // 循環(huán)處理importClassNames類中再包含的import類

? ? ? ? ? ? ? ? ? processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);

? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {

? ? ? ? ? ? ? // Candidate class is an ImportBeanDefinitionRegistrar ->

? ? ? ? ? ? ? // delegate to it to register additional bean definitions

? ? ? ? ? ? ? Class<?> candidateClass = candidate.loadClass();

? ? ? ? ? ? ? // 直接實例化ImportBeanDefinitionRegistrar 類

? ? ? ? ? ? ? ImportBeanDefinitionRegistrar registrar =

? ? ? ? ? ? ? ? ? ? ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,

? ? ? ? ? ? ? ? ? ? ? ? ? this.environment, this.resourceLoader, this.registry);

? ? ? ? ? ? ? // 將ImportBeanDefinitionRegistrar 類加入到importBeanDefinitionRegistrars集合中

? ? ? ? ? ? ? // 會在ConfigurationClassPostProcessor第69行代碼進行處理

? ? ? ? ? ? ? configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

? ? ? ? ? ? }

? ? ? ? ? ? else {

? ? ? ? ? ? ? // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->

? ? ? ? ? ? ? // process it as an @Configuration class

? ? ? ? ? ? ? this.importStack.registerImport(

? ? ? ? ? ? ? ? ? ? currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());

? ? ? ? ? ? ? // 非ImportSelector or ImportBeanDefinitionRegistrar直接處理,放入BeanFactory中

? ? ? ? ? ? ? processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);

? ? ? ? ? ? }

? ? ? ? }

? ? ? }

? ? ? ......

? }

}

通過以上的步驟已將Import中的類注入到BeanFacotry的beanDefinitionMap中等待實例化(ImportBeanDefinitionRegistrar類型的Bean需要通過下面的方式處理才能放入)参萄,回到ConfigurationClassPostProcessor的69行代碼(this.reader.loadBeanDefinitions(configClasses);)卫枝,調(diào)用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions進行處理。

ConfigurationClassBeanDefinitionReader

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {

? TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();

? for (ConfigurationClass configClass : configurationModel) {

? ? ? loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);

? }

}

private void loadBeanDefinitionsForConfigurationClass(

? ? ? ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

? ......

? loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

? // 獲取所有ImportBeanDefinitionRegistrars進行處理

? loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());

}

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {

? registrars.forEach((registrar, metadata) ->

? ? ? ? // 調(diào)用繼承ImportBeanDefinitionRegistrar類中的registerBeanDefinitions將Bean注入到BeanFactory

? ? ? ? registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));

}

到這一步Import的所有類已注冊到BeanFactory中讹挎,那么什么時候?qū)@些類進行初始化呢校赤?回到AnnotationConfigApplicationContext(即AbstractApplicationContext)的refresh方法,通過finishBeanFactoryInitialization(beanFactory)實例化Bean筒溃。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末马篮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子怜奖,更是在濱河造成了極大的恐慌浑测,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歪玲,死亡現(xiàn)場離奇詭異迁央,居然都是意外死亡,警方通過查閱死者的電腦和手機滥崩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門岖圈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钙皮,你說我怎么就攤上這事蜂科。” “怎么了短条?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵崇摄,是天一觀的道長。 經(jīng)常有香客問我慌烧,道長逐抑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任屹蚊,我火速辦了婚禮厕氨,結果婚禮上进每,老公的妹妹穿的比我還像新娘。我一直安慰自己命斧,他們只是感情好田晚,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著国葬,像睡著了一般贤徒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上汇四,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天接奈,我揣著相機與錄音,去河邊找鬼通孽。 笑死序宦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的背苦。 我是一名探鬼主播互捌,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼行剂!你這毒婦竟也來了秕噪?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤厚宰,失蹤者是張志新(化名)和其女友劉穎巢价,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體固阁,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡壤躲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了备燃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碉克。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖并齐,靈堂內(nèi)的尸體忽然破棺而出漏麦,到底是詐尸還是另有隱情,我是刑警寧澤况褪,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布撕贞,位于F島的核電站,受9級特大地震影響测垛,放射性物質(zhì)發(fā)生泄漏捏膨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望号涯。 院中可真熱鬧目胡,春花似錦、人聲如沸链快。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽域蜗。三九已至巨双,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間霉祸,已是汗流浹背筑累。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脉执,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓戒劫,卻偏偏與公主長得像半夷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子迅细,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

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