請(qǐng)別再問Spring Bean的生命周期了烂完!

Spring Bean的生命周期是Spring面試熱點(diǎn)問題民褂。這個(gè)問題即考察對(duì)Spring的微觀了解茄菊,又考察對(duì)Spring的宏觀認(rèn)識(shí),想要答好并不容易赊堪!本文希望能夠從源碼角度入手买羞,幫助面試者徹底搞定Spring Bean的生命周期。

只有四個(gè)雹食!

是的,Spring Bean的生命周期只有這四個(gè)階段期丰。把這四個(gè)階段和每個(gè)階段對(duì)應(yīng)的擴(kuò)展點(diǎn)糅合在一起雖然沒有問題群叶,但是這樣非常凌亂,難以記憶钝荡。要徹底搞清楚Spring的生命周期街立,首先要把這四個(gè)階段牢牢記住。實(shí)例化和屬性賦值對(duì)應(yīng)構(gòu)造方法和setter方法的注入埠通,初始化和銷毀是用戶能自定義擴(kuò)展的兩個(gè)階段赎离。在這四步之間穿插的各種擴(kuò)展點(diǎn),稍后會(huì)講端辱。

  1. 實(shí)例化 Instantiation
  2. 屬性賦值 Populate
  3. 初始化 Initialization
  4. 銷毀 Destruction

實(shí)例化 -> 屬性賦值 -> 初始化 -> 銷毀

主要邏輯都在doCreate()方法中梁剔,邏輯很清晰,就是順序調(diào)用以下三個(gè)方法舞蔽,這三個(gè)方法與三個(gè)生命周期階段一一對(duì)應(yīng)荣病,非常重要,在后續(xù)擴(kuò)展接口分析中也會(huì)涉及渗柿。

  1. createBeanInstance() -> 實(shí)例化
  2. populateBean() -> 屬性賦值
  3. initializeBean() -> 初始化

源碼如下个盆,能證明實(shí)例化,屬性賦值和初始化這三個(gè)生命周期的存在朵栖。關(guān)于本文的Spring源碼都將忽略無關(guān)部分颊亮,便于理解:

// 忽略了無關(guān)代碼
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (instanceWrapper == null) {
       // 實(shí)例化階段!
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
       // 屬性賦值階段陨溅!
      populateBean(beanName, mbd, instanceWrapper);
       // 初始化階段终惑!
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }

   
   }

至于銷毀,是在容器關(guān)閉時(shí)調(diào)用的声登,詳見ConfigurableApplicationContext#close()

常用擴(kuò)展點(diǎn)

Spring生命周期相關(guān)的常用擴(kuò)展點(diǎn)非常多狠鸳,所以問題不是不知道揣苏,而是記不住或者記不牢。其實(shí)記不住的根本原因還是不夠了解件舵,這里通過源碼+分類的方式幫大家記憶卸察。

第一大類:影響多個(gè)Bean的接口

實(shí)現(xiàn)了這些接口的Bean會(huì)切入到多個(gè)Bean的生命周期中。正因?yàn)槿绱饲觯@些接口的功能非常強(qiáng)大坑质,Spring內(nèi)部擴(kuò)展也經(jīng)常使用這些接口,例如自動(dòng)注入以及AOP的實(shí)現(xiàn)都和他們有關(guān)临梗。

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

這兩兄弟可能是Spring擴(kuò)展中最重要的兩個(gè)接口涡扼!InstantiationAwareBeanPostProcessor作用于實(shí)例化階段的前后,BeanPostProcessor作用于初始化階段的前后盟庞。正好和第一吃沪、第三個(gè)生命周期階段對(duì)應(yīng)。通過圖能更好理解:

未命名文件 (1).png

InstantiationAwareBeanPostProcessor實(shí)際上繼承了BeanPostProcessor接口什猖,嚴(yán)格意義上來看他們不是兩兄弟票彪,而是兩父子。但是從生命周期角度我們重點(diǎn)關(guān)注其特有的對(duì)實(shí)例化階段的影響不狮,圖中省略了從BeanPostProcessor繼承的方法降铸。

InstantiationAwareBeanPostProcessor extends BeanPostProcessor
InstantiationAwareBeanPostProcessor源碼分析:
  • postProcessBeforeInstantiation調(diào)用點(diǎn),忽略無關(guān)代碼:
@Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // postProcessBeforeInstantiation方法調(diào)用點(diǎn)摇零,這里就不跟進(jìn)了推掸,
            // 有興趣的同學(xué)可以自己看下,就是for循環(huán)調(diào)用所有的InstantiationAwareBeanPostProcessor
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        
        try {   
            // 上文提到的doCreateBean方法驻仅,可以看到
            // postProcessBeforeInstantiation方法在創(chuàng)建Bean之前調(diào)用
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        
    }

可以看到谅畅,postProcessBeforeInstantiation在doCreateBean之前調(diào)用,也就是在bean實(shí)例化之前調(diào)用的雾家,英文源碼注釋解釋道該方法的返回值會(huì)替換原本的Bean作為代理铃彰,這也是Aop等功能實(shí)現(xiàn)的關(guān)鍵點(diǎn)。

  • postProcessAfterInstantiation調(diào)用點(diǎn)芯咧,忽略無關(guān)代碼:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

   // 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.
   boolean continueWithPropertyPopulation = true;
    // InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
    // 方法作為屬性賦值的前置檢查條件牙捉,在屬性賦值之前執(zhí)行,能夠影響是否進(jìn)行屬性賦值敬飒!
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }

   // 忽略后續(xù)的屬性賦值操作代碼
}

可以看到該方法在屬性賦值方法內(nèi)邪铲,但是在真正執(zhí)行賦值操作之前。其返回值為boolean无拗,返回false時(shí)可以阻斷屬性賦值階段(continueWithPropertyPopulation = false;)带到。

關(guān)于BeanPostProcessor執(zhí)行階段的源碼穿插在下文Aware接口的調(diào)用時(shí)機(jī)分析中,因?yàn)椴糠諥ware功能的就是通過他實(shí)現(xiàn)的!只需要先記住BeanPostProcessor在初始化前后調(diào)用就可以了英染。

第二大類:只調(diào)用一次的接口

這一大類接口的特點(diǎn)是功能豐富揽惹,常用于用戶自定義擴(kuò)展被饿。
第二大類中又可以分為兩類:

  1. Aware類型的接口
  2. 生命周期接口
無所不知的Aware

Aware類型的接口的作用就是讓我們能夠拿到Spring容器中的一些資源√虏基本都能夠見名知意狭握,Aware之前的名字就是可以拿到什么資源,例如BeanNameAware可以拿到BeanName疯溺,以此類推论颅。調(diào)用時(shí)機(jī)需要注意:所有的Aware方法都是在初始化階段之前調(diào)用的!
Aware接口眾多囱嫩,這里同樣通過分類的方式幫助大家記憶恃疯。
Aware接口具體可以分為兩組,至于為什么這么分墨闲,詳見下面的源碼分析今妄。如下排列順序同樣也是Aware接口的執(zhí)行順序,能夠見名知意的接口不再解釋鸳碧。

Aware Group1

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware

Aware Group2

  1. EnvironmentAware
  2. EmbeddedValueResolverAware 這個(gè)知道的人可能不多蛙奖,實(shí)現(xiàn)該接口能夠獲取Spring EL解析器,用戶的自定義注解需要支持spel表達(dá)式的時(shí)候可以使用杆兵,非常方便。
  3. ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 這幾個(gè)接口可能讓人有點(diǎn)懵仔夺,實(shí)際上這幾個(gè)接口可以一起記琐脏,其返回值實(shí)質(zhì)上都是當(dāng)前的ApplicationContext對(duì)象,因?yàn)锳pplicationContext是一個(gè)復(fù)合接口缸兔,如下:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}

這里涉及到另一道面試題日裙,ApplicationContext和BeanFactory的區(qū)別,可以從ApplicationContext繼承的這幾個(gè)接口入手惰蜜,除去BeanFactory相關(guān)的兩個(gè)接口就是ApplicationContext獨(dú)有的功能昂拂,這里不詳細(xì)說明。

Aware調(diào)用時(shí)機(jī)源碼分析

詳情如下抛猖,忽略了部分無關(guān)代碼格侯。代碼位置就是我們上文提到的initializeBean方法詳情,這也說明了Aware都是在初始化階段之前調(diào)用的财著!

    // 見名知意联四,初始化階段調(diào)用的方法
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

        // 這里調(diào)用的是Group1中的三個(gè)Bean開頭的Aware
        invokeAwareMethods(beanName, bean);

        Object wrappedBean = bean;
        
        // 這里調(diào)用的是Group2中的幾個(gè)Aware,
        // 而實(shí)質(zhì)上這里就是前面所說的BeanPostProcessor的調(diào)用點(diǎn)撑教!
        // 也就是說與Group1中的Aware不同朝墩,這里是通過BeanPostProcessor(ApplicationContextAwareProcessor)實(shí)現(xiàn)的。
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        // 下文即將介紹的InitializingBean調(diào)用點(diǎn)
        invokeInitMethods(beanName, wrappedBean, mbd);
        // BeanPostProcessor的另一個(gè)調(diào)用點(diǎn)
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

        return wrappedBean;
    }

可以看到并不是所有的Aware接口都使用同樣的方式調(diào)用伟姐。Bean××Aware都是在代碼中直接調(diào)用的收苏,而ApplicationContext相關(guān)的Aware都是通過BeanPostProcessor#postProcessBeforeInitialization()實(shí)現(xiàn)的亿卤。感興趣的可以自己看一下ApplicationContextAwareProcessor這個(gè)類的源碼,就是判斷當(dāng)前創(chuàng)建的Bean是否實(shí)現(xiàn)了相關(guān)的Aware方法鹿霸,如果實(shí)現(xiàn)了會(huì)調(diào)用回調(diào)方法將資源傳遞給Bean排吴。
至于Spring為什么這么實(shí)現(xiàn),應(yīng)該沒什么特殊的考量杜跷。也許和Spring的版本升級(jí)有關(guān)紊撕∩睿基于對(duì)修改關(guān)閉,對(duì)擴(kuò)展開放的原則,Spring對(duì)一些新的Aware采用了擴(kuò)展的方式添加丛肢。

BeanPostProcessor的調(diào)用時(shí)機(jī)也能在這里體現(xiàn),包圍住invokeInitMethods方法吱殉,也就說明了在初始化階段的前后執(zhí)行攒霹。

關(guān)于Aware接口的執(zhí)行順序,其實(shí)只需要記住第一組在第二組執(zhí)行之前就行了扣泊。每組中各個(gè)Aware方法的調(diào)用順序其實(shí)沒有必要記近范,有需要的時(shí)候點(diǎn)進(jìn)源碼一看便知。

簡(jiǎn)單的兩個(gè)生命周期接口

至于剩下的兩個(gè)生命周期接口就很簡(jiǎn)單了延蟹,實(shí)例化和屬性賦值都是Spring幫助我們做的评矩,能夠自己實(shí)現(xiàn)的有初始化和銷毀兩個(gè)生命周期階段。

  1. InitializingBean 對(duì)應(yīng)生命周期的初始化階段阱飘,在上面源碼的invokeInitMethods(beanName, wrappedBean, mbd);方法中調(diào)用斥杜。
    有一點(diǎn)需要注意,因?yàn)锳ware方法都是執(zhí)行在初始化方法之前沥匈,所以可以在初始化方法中放心大膽的使用Aware接口獲取的資源蔗喂,這也是我們自定義擴(kuò)展Spring的常用方式。
    除了實(shí)現(xiàn)InitializingBean接口之外還能通過注解或者xml配置的方式指定初始化方法高帖,至于這幾種定義方式的調(diào)用順序其實(shí)沒有必要記缰儿。因?yàn)檫@幾個(gè)方法對(duì)應(yīng)的都是同一個(gè)生命周期,只是實(shí)現(xiàn)方式不同散址,我們一般只采用其中一種方式乖阵。
  2. DisposableBean 類似于InitializingBean,對(duì)應(yīng)生命周期的銷毀階段预麸,以ConfigurableApplicationContext#close()方法作為入口义起,實(shí)現(xiàn)是通過循環(huán)取所有實(shí)現(xiàn)了DisposableBean接口的Bean然后調(diào)用其destroy()方法 。感興趣的可以自行跟一下源碼师崎。

擴(kuò)展閱讀: BeanPostProcessor 注冊(cè)時(shí)機(jī)與執(zhí)行順序

注冊(cè)時(shí)機(jī)

我們知道BeanPostProcessor也會(huì)注冊(cè)為Bean默终,那么Spring是如何保證BeanPostProcessor在我們的業(yè)務(wù)Bean之前初始化完成呢?
請(qǐng)看我們熟悉的refresh()方法的源碼,省略部分無關(guān)代碼:

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 所有BeanPostProcesser初始化的調(diào)用點(diǎn)
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 所有單例非懶加載Bean的調(diào)用點(diǎn)
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

    }

可以看出齐蔽,Spring是先執(zhí)行registerBeanPostProcessors()進(jìn)行BeanPostProcessors的注冊(cè)两疚,然后再執(zhí)行finishBeanFactoryInitialization初始化我們的單例非懶加載的Bean。

執(zhí)行順序

BeanPostProcessor有很多個(gè)含滴,而且每個(gè)BeanPostProcessor都影響多個(gè)Bean诱渤,其執(zhí)行順序至關(guān)重要,必須能夠控制其執(zhí)行順序才行谈况。關(guān)于執(zhí)行順序這里需要引入兩個(gè)排序相關(guān)的接口:PriorityOrdered勺美、Ordered

  • PriorityOrdered是一等公民,首先被執(zhí)行碑韵,PriorityOrdered公民之間通過接口返回值排序

  • Ordered是二等公民赡茸,然后執(zhí)行,Ordered公民之間通過接口返回值排序

  • 都沒有實(shí)現(xiàn)是三等公民祝闻,最后執(zhí)行

在以下源碼中占卧,可以很清晰的看到Spring注冊(cè)各種類型BeanPostProcessor的邏輯,根據(jù)實(shí)現(xiàn)不同排序接口進(jìn)行分組联喘。優(yōu)先級(jí)高的先加入华蜒,優(yōu)先級(jí)低的后加入。

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 首先豁遭,加入實(shí)現(xiàn)了PriorityOrdered接口的BeanPostProcessors叭喜,順便根據(jù)PriorityOrdered排了序
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();

            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 然后,加入實(shí)現(xiàn)了Ordered接口的BeanPostProcessors蓖谢,順便根據(jù)Ordered排了序
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();

            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后加入其他常規(guī)的BeanPostProcessors
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    if (!processedBeans.contains(ppName)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                        reiterate = true;
                    }
                }
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
            }

根據(jù)排序接口返回值排序域滥,默認(rèn)升序排序,返回值越低優(yōu)先級(jí)越高蜈抓。

    /**
     * Useful constant for the highest precedence value.
     * @see java.lang.Integer#MIN_VALUE
     */
    int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

    /**
     * Useful constant for the lowest precedence value.
     * @see java.lang.Integer#MAX_VALUE
     */
    int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

PriorityOrdered、Ordered接口作為Spring整個(gè)框架通用的排序接口昂儒,在Spring中應(yīng)用廣泛沟使,也是非常重要的接口。

總結(jié)

Spring Bean的生命周期分為四個(gè)階段多個(gè)擴(kuò)展點(diǎn)渊跋。擴(kuò)展點(diǎn)又可以分為影響多個(gè)Bean影響單個(gè)Bean腊嗡。整理如下:
四個(gè)階段

  • 實(shí)例化 Instantiation
  • 屬性賦值 Populate
  • 初始化 Initialization
  • 銷毀 Destruction

多個(gè)擴(kuò)展點(diǎn)

  • 影響多個(gè)Bean
    • BeanPostProcessor
    • InstantiationAwareBeanPostProcessor
  • 影響單個(gè)Bean
    • Aware
      • Aware Group1
        • BeanNameAware
        • BeanClassLoaderAware
        • BeanFactoryAware
      • Aware Group2
        • EnvironmentAware
        • EmbeddedValueResolverAware
        • ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
    • 生命周期
      • InitializingBean
      • DisposableBean

至此,Spring Bean的生命周期介紹完畢拾酝,由于作者水平有限難免有疏漏燕少,歡迎留言糾錯(cuò)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蒿囤,一起剝皮案震驚了整個(gè)濱河市客们,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖底挫,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恒傻,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡建邓,警方通過查閱死者的電腦和手機(jī)盈厘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來官边,“玉大人沸手,你說我怎么就攤上這事∽⒉荆” “怎么了契吉?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)滩援。 經(jīng)常有香客問我栅隐,道長(zhǎng),這世上最難降的妖魔是什么玩徊? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任租悄,我火速辦了婚禮,結(jié)果婚禮上恩袱,老公的妹妹穿的比我還像新娘泣棋。我一直安慰自己,他們只是感情好畔塔,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布潭辈。 她就那樣靜靜地躺著,像睡著了一般澈吨。 火紅的嫁衣襯著肌膚如雪把敢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天谅辣,我揣著相機(jī)與錄音修赞,去河邊找鬼。 笑死桑阶,一個(gè)胖子當(dāng)著我的面吹牛柏副,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚣录,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼割择,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了萎河?” 一聲冷哼從身側(cè)響起荔泳,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤蕉饼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后换可,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體椎椰,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年沾鳄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慨飘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡译荞,死狀恐怖瓤的,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吞歼,我是刑警寧澤圈膏,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站篙骡,受9級(jí)特大地震影響稽坤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜糯俗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一尿褪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧得湘,春花似錦杖玲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)囤采。三九已至,卻和暖如春蕉毯,著一層夾襖步出監(jiān)牢的瞬間黎泣,已是汗流浹背抒倚。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工坷澡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留托呕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像项郊,于是被迫代替她去往敵國(guó)和親馅扣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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

  • 本來是準(zhǔn)備看一看Spring源碼的着降。然后在知乎上看到來一個(gè)帖子差油,說有一群**自己連Spring官方文檔都沒有完全讀...
    此魚不得水閱讀 6,926評(píng)論 4 21
  • 在 Spring 中,我們可以從兩個(gè)層面定義 Bean 的生命周期: Bean 的作用范圍任洞。 實(shí)例化 Bean 時(shí)...
    deniro閱讀 2,594評(píng)論 0 8
  • 在分析 Spring Bean 實(shí)例化過程中提到 Spring 并不是一啟動(dòng)容器就開啟 bean 的實(shí)例化進(jìn)程蓄喇,只...
    Java_蘇先生閱讀 2,562評(píng)論 0 4
  • 用了好久的spring,對(duì)bean的生命周期一直 一知半解交掏。今天百度谷歌詳細(xì)了解了下,在此做個(gè)整理妆偏。 bean的生...
    瘋狂的哈丘閱讀 1,340評(píng)論 1 4
  • 上一篇學(xué)習(xí)了容器的概念,那么容器中的bean到底是如何管理的盅弛,這就涉及到了另一個(gè)核心概念 bean的生命周期 我們...
    lionel880閱讀 737評(píng)論 0 0