<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:兄弟你來(lái)闡述一下Spring框架中Bean的生命周期?

          共 8134字,需瀏覽 17分鐘

           ·

          2020-09-26 04:59

          今天阿粉給大家?guī)?lái)的是關(guān)于Spring的另外的一道高頻面試題,而且是非常非常高頻的面試題,那就是Spring中的Bean的生命周期。

          1.Bean的生命周期

          關(guān)于Bean的生命周期,如果我們不談這個(gè)Spring的話,實(shí)際上很多人都會(huì)想到New,通過(guò) New 對(duì)象的形式來(lái)實(shí)現(xiàn)對(duì) Bean的實(shí)例化操作,而在我們不再使用 Bean 了之后,這時(shí)候我們的 Java 就會(huì)對(duì)這個(gè)指定的 Bean 來(lái)進(jìn)行垃圾回收了。

          但是對(duì)于Spring來(lái)說(shuō),Bean的生命周期可能就比較讓人頭疼了,畢竟 Spring 這么復(fù)雜,而且里面的對(duì) Bean 管理的非常的有邏輯了,每一層都有每一層的步驟。

          如果現(xiàn)在我們?nèi)グ俣壬厦嫒ニ阉魉械年P(guān)于Spring的Bean的生命周期,很多人會(huì)把這個(gè)解釋出來(lái)

          • 在IoC容器啟動(dòng)之后,并不會(huì)馬上就實(shí)例化相應(yīng)的bean,此時(shí)容器僅僅擁有所有對(duì)象的BeanDefinition(BeanDefinition:是容器依賴某些工具加載的XML配置信息進(jìn)行解析和分析,并將分析后的信息編組為相應(yīng)的BeanDefinition)。只有當(dāng)getBean()調(diào)用時(shí)才是有可能觸發(fā)Bean實(shí)例化階段的活動(dòng)

          而有一些內(nèi)容就不會(huì)說(shuō)解釋的很透徹,比如說(shuō)為什么說(shuō)只有當(dāng) getBean() 調(diào)用的時(shí)候才有可能觸發(fā)Bean的實(shí)例化。

          2.生命周期流程圖

          2.1簡(jiǎn)化版圖解

          而這圖解中,把 Spring 中 Bean 的生命周期分成了好幾個(gè)步驟,分別是:

          1. 通過(guò)構(gòu)造方法實(shí)例化 Bean 對(duì)象。

          2. 通過(guò) setter 方法設(shè)置對(duì)象的屬性。

          3. 通過(guò)Aware,也就是他的子類BeanNameAware,調(diào)用Bean的setBeanName()方法傳遞Bean的ID(XML里面注冊(cè)的ID),setBeanName方法是在bean初始化時(shí)調(diào)用的,通過(guò)這個(gè)方法可以得到BeanFactory和 Bean 在 XML 里面注冊(cè)的ID。

          4. 如果說(shuō) Bean 實(shí)現(xiàn)了 BeanFactoryAware,那么工廠調(diào)用setBeanFactory(BeanFactory var1) 傳入的參數(shù)也是自身。

          5. 把 Bean 實(shí)例傳遞給 BeanPostProcessor 中的 postProcessBeforeInitialization 前置方法。

          6. 完成 Bean 的初始化

          7. 把 Bean 實(shí)例傳遞給 BeanPostProcessor 中的 postProcessAfterInitialization 后置方法。

          8. 此時(shí) Bean 已經(jīng)能夠正常時(shí)候,在最后的時(shí)候調(diào)用 DisposableBean 中的 destroy 方法進(jìn)行銷毀處理。

          而阿粉覺(jué)得如果面試官在面試的時(shí)候問(wèn)到這個(gè)問(wèn)題的時(shí)候,你從圖解開始入手,然后把這些都說(shuō)給他之后,那么相對(duì)應(yīng)的,這現(xiàn)在這些答案,如果不繼續(xù)的深挖內(nèi)容,可能已經(jīng)就足夠了。

          而接下來(lái)還要從根本上來(lái)論證阿粉所寫的內(nèi)容。

          而我們對(duì)這詳細(xì)的可能有時(shí)候難以記憶,可能還是理解不深,而我們可以從四到五個(gè)方面來(lái)記憶,

          • 構(gòu)造實(shí)例化
          • 屬性賦值
          • 完成初始化
          • (前后處理)
          • 使用后銷毀

          而從這五個(gè)方面來(lái)記憶,或許就能把這個(gè)圖擴(kuò)展開,從而言簡(jiǎn)意賅的回答面試官的問(wèn)題。

          代碼驗(yàn)證


          package com.yld.bean;

          import org.springframework.beans.factory.BeanNameAware;

          public class Person implements BeanNameAware {

          private String name;

          /**
          * 實(shí)現(xiàn)類上的override方法
          * @param s
          */
          @Override
          public void setBeanName(String s) {
          System.out.println("調(diào)用BeanNameAware中的setName賦值");
          }

          public Person() {
          }

          /**
          * 屬性賦值
          * @param name
          */
          public void setName(String name) {
          System.out.println("設(shè)置對(duì)象屬性setName()..");
          this.name = name;
          }

          /**
          * Bean初始化
          */
          public void initBeanPerson() {
          System.out.println("初始化Bean");
          }

          /**
          * Bean方法使用:說(shuō)話
          */
          public void speak() {
          System.out.println("使用Bean的Speak方法");
          }

          /**
          * 銷毀Bean
          */
          public void destroyBeanPerson() {
          System.out.println("銷毀Bean");
          }


          }

          Main方法

          public static void main(String[] args) {
          ClassPathXmlApplicationContext pathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
          Person person = (Person)pathXmlApplicationContext.getBean("person");
          person.speak();
          pathXmlApplicationContext.close();
          }

          運(yùn)行結(jié)果展示

          D:\develop\JDK8\jdk1.8.0_181\bin\java.exe "-javaagent:D:\develop\IDEA\IntelliJ IDEA 2018.1.8\lib\idea_rt.jar=63906:D:\develop\IDEA\IntelliJ IDEA 2018.1.8\bin" -Dfile.encoding=UTF-8 -classpath D:\develop\JDK8\jdk1.8.0_181\jre\lib\charsets.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\deploy.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\dnsns.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\jaccess.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\localedata.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\nashorn.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\sunec.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\ext\zipfs.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\javaws.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\jce.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\jfr.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\jfxswt.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\jsse.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\management-agent.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\plugin.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\resources.jar;D:\develop\JDK8\jdk1.8.0_181\jre\lib\rt.jar;D:\develop\IDEAProject\KaiYuan\target\classes;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter\2.1.8.RELEASE\spring-boot-starter-2.1.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot\2.1.8.RELEASE\spring-boot-2.1.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-context\5.1.9.RELEASE\spring-context-5.1.9.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-aop\5.1.9.RELEASE\spring-aop-5.1.9.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-beans\5.1.9.RELEASE\spring-beans-5.1.9.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-expression\5.1.9.RELEASE\spring-expression-5.1.9.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.1.8.RELEASE\spring-boot-autoconfigure-2.1.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.1.8.RELEASE\spring-boot-starter-logging-2.1.8.RELEASE.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\Users\Administrator\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.11.2\log4j-to-slf4j-2.11.2.jar;C:\Users\Administrator\.m2\repository\org\apache\logging\log4j\log4j-api\2.11.2\log4j-api-2.11.2.jar;C:\Users\Administrator\.m2\repository\org\slf4j\jul-to-slf4j\1.7.28\jul-to-slf4j-1.7.28.jar;C:\Users\Administrator\.m2\repository\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-core\5.1.9.RELEASE\spring-core-5.1.9.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-jcl\5.1.9.RELEASE\spring-jcl-5.1.9.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\yaml\snakeyaml\1.23\snakeyaml-1.23.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-api\1.7.28\slf4j-api-1.7.28.jar com.yld.bean.Test
          16:54:58.817 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@123772c4
          16:54:59.074 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [applicationContext.xml]
          16:54:59.121 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'person'

          設(shè)置對(duì)象屬性setName()..

          調(diào)用BeanNameAware中的setName賦值

          初始化Bean

          使用Bean的Speak方法

          16:54:59.232 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@123772c4, started on Sun Jun 07 16:54:58 CST 2020

          銷毀Bean

          Process finished with exit code 0

          和大家預(yù)想的是不是一樣的呢? 在用案例回答面試官之后,我們最好還是要研究一下源碼的部分,畢竟研究清楚了,會(huì)理解的更深刻不是么?

          InstantiationAwareBeanPostProcessor

          這個(gè)類是繼承的 BeanPostProcessor 而這個(gè)類的作用是什么呢?源碼注釋解釋的是這樣子的:

          方法一:

          @Nullable
          default Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
          return null;
          }
          應(yīng)用這個(gè)Bean處理器在目標(biāo)Bean實(shí)例化之前。返回的bean對(duì)象可能是一個(gè)代理bean的使用而不是目標(biāo),

          也就是說(shuō)postProcessBeforeInstantiation在bean實(shí)例化之前調(diào)用的,這是不是也是我們?cè)诿嬖囍辛硗獾囊粋€(gè)面試點(diǎn) AOP 的使用呢?到時(shí)候面試官讓你舉例子的時(shí)候,你直接用這個(gè) Spring 里面的源碼給他解釋,分分鐘讓面試官對(duì)你刮目想看呀有木有。

          方法二:可以看到該方法在屬性賦值方法內(nèi),但是在真正執(zhí)行賦值操作之前。其返回值為boolean。

          default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
          return true;
          }

          大家是不是還可以這么理解,如果返回值為false的話,那么就出現(xiàn)了賦值失敗,也就是間接阻斷賦值了。

          而初始化的類同樣的 BeanPostProcessor

          方法一:

          任何Bean之前初始化回調(diào)如初始化Bean的屬性設(shè)置后
          @Nullable
          default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
          return bean;
          }

          方法二:

          應(yīng)用這個(gè)Bean后置處理程序給定新的Bean實(shí)例,任何Bean初始化后回調(diào)(如初始化Bean的屬性設(shè)置后{@code}或一個(gè)自定義的init方法)。bean已經(jīng)填充屬性值。返回的bean實(shí)例可能是原始的包裝器。
          @Nullable
          default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          return bean;
          }


          同樣注釋翻譯出來(lái)的意思也是很明確的,這也是阿粉為什么喜歡自己下載個(gè)插件去看注釋,畢竟源碼這個(gè)東西如果看別人理解的和自己理解的,有時(shí)候差距也是很大的。

          關(guān)于這個(gè)SpringBean的高頻面試題,你會(huì)回答了么?

          文獻(xiàn)參考

          《Spring源碼深度解析》

          代碼參考

          Spring 了解Bean的一生(生命周期)


          < END >

          喜歡就點(diǎn)下“”、"在看"


          關(guān)注 Stephen,一起學(xué)習(xí),一起成長(zhǎng)。



          瀏覽 32
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美高清中文字幕精品日韩不卡国产在线一区 | 国产尤物视频 | 三级欧美视频麻豆传媒 | 婷婷五月六月丁香 | 成人Av影院三级片 |