国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring源碼:Bean的生命周期(二)

這篇具有很好參考價(jià)值的文章主要介紹了Spring源碼:Bean的生命周期(二)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言

讓我們繼續(xù)講解Spring的Bean實(shí)例化過程。在上一節(jié)中,我們已經(jīng)講解了Spring是如何將Bean定義加入到IoC容器中,并使用合并的Bean定義來包裝原始的Bean定義。接下來,我們將繼續(xù)講解Spring的 getBean() 方法,特別是針對 FactoryBean 的解析。

getBean() 方法中,Spring還支持對 FactoryBean 進(jìn)行特殊處理。FactoryBean 是一個(gè)能夠生成Bean實(shí)例的工廠Bean,其定義了 getObject() 方法,返回的是一個(gè)由工廠Bean管理的對象實(shí)例。在使用 getBean() 方法獲取 FactoryBean 類型的Bean時(shí),Spring會(huì)首先獲取 FactoryBean 的實(shí)例,然后調(diào)用其 getObject() 方法來獲取由工廠Bean創(chuàng)建的實(shí)際Bean實(shí)例。

因此,在使用 getBean() 方法獲取Bean實(shí)例時(shí),我們需要注意是否需要對 FactoryBean 進(jìn)行特殊處理。如果需要獲取 FactoryBean 的實(shí)例而不是它所管理的對象實(shí)例,可以在Bean名稱前加上 & 符號來進(jìn)行標(biāo)識。例如:&myFactoryBean 表示獲取 myFactoryBean 的實(shí)例。但是博主看到第一篇源碼寫的篇幅確實(shí)有些長,可能對于大家伙的碎片化時(shí)間掌握的不是很充分,所以以后我會(huì)盡力控制篇幅長度,既保證邏輯的連續(xù)性也保證盡快可以看完,那么接下來開始進(jìn)入正題getbean方法之FactoryBean解析。

FactoryBean

所有符合過濾條件的Bean在Spring解析后都會(huì)被轉(zhuǎn)化為合并后的Bean定義。盡管Spring提供了 getBean() 方法用于獲取Bean實(shí)例,但實(shí)際上它底層仍然使用 createBean() 方法來創(chuàng)建Bean實(shí)例。在創(chuàng)建Bean實(shí)例之前,Spring先對當(dāng)前Bean定義進(jìn)行判斷,以確定其是否為 FactoryBean 類型:

public void preInstantiateSingletons() throws BeansException {  
   if (logger.isTraceEnabled()) {  
      logger.trace("Pre-instantiating singletons in " + this);  
   }  
  
   // Iterate over a copy to allow for init methods which in turn register new bean definitions.  
 // While this may not be part of the regular factory bootstrap, it does otherwise work fine.  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);  
  
   // Trigger initialization of all non-lazy singleton beans...  
  for (String beanName : beanNames) {  
      // 獲取合并后的BeanDefinition  
  RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);  
  
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {  
         if (isFactoryBean(beanName)) {  
            // 獲取FactoryBean對象  
  Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);  
            if (bean instanceof FactoryBean) {  
               FactoryBean<?> factory = (FactoryBean<?>) bean;  
               boolean isEagerInit;  
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {  
                  isEagerInit = AccessController.doPrivileged(  
                        (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,  
                        getAccessControlContext());  
               }  
               else {  
                  isEagerInit = (factory instanceof SmartFactoryBean &&  
                        ((SmartFactoryBean<?>) factory).isEagerInit());  
               }  
               if (isEagerInit) {  
                  // 創(chuàng)建真正的Bean對象(getObject()返回的對象)  
  getBean(beanName);  
               }  
            }  
         }  
         else {  
            // 創(chuàng)建Bean對象  
  getBean(beanName);  
         }  
      }  
   }  
  
   // 所有的非懶加載單例Bean都創(chuàng)建完了后  
  // Trigger post-initialization callback for all applicable beans...  
  for (String beanName : beanNames) {  
      Object singletonInstance = getSingleton(beanName);  
      if (singletonInstance instanceof SmartInitializingSingleton) {  
         StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")  
               .tag("beanName", beanName);  
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;  
         if (System.getSecurityManager() != null) {  
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {  
               smartSingleton.afterSingletonsInstantiated();  
               return null;  
            }, getAccessControlContext());  
         }  
         else {  
            smartSingleton.afterSingletonsInstantiated();  
         }  
         smartInitialize.end();  
      }  
   }  
}

他的源碼邏輯大致如下:

  1. Spring會(huì)根據(jù) beanNamebean 定義 Map 中獲取當(dāng)前合并的 Bean 定義。
  2. Spring會(huì)對當(dāng)前 Bean 定義進(jìn)行判斷,包括判斷當(dāng)前 Bean 是否為抽象的、是否為單例、是否懶加載,以及是否為 FactoryBean。如果是 FactoryBean,則會(huì)走 FactoryBean 的創(chuàng)建邏輯,否則會(huì)走單例 Bean 的創(chuàng)建邏輯。
  3. 當(dāng)所有單例非懶加載的 Bean 創(chuàng)建完成后,Spring會(huì)遍歷所有單例 Bean,判斷其是否為 SmartInitializingSingleton 類型。如果是,則會(huì)自動(dòng)調(diào)用 afterSingletonsInstantiated 方法。

isFactoryBean

由于創(chuàng)建 Bean 的邏輯比較復(fù)雜,其中包含了許多細(xì)節(jié),因此,在這里我們特別提到了一個(gè)方法 isFactoryBean()。之所以要提到這個(gè)方法,是因?yàn)镾pring支持使用 FactoryBean 來創(chuàng)建復(fù)雜對象。下面是該方法的主要源碼:

public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {  
   String beanName = transformedBeanName(name);  
   Object beanInstance = getSingleton(beanName, false);  
   if (beanInstance != null) {  
      return (beanInstance instanceof FactoryBean);  
   }  
   // No singleton instance found -> check bean definition.  
  if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {  
      // No bean definition found in this factory -> delegate to parent.  
  return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);  
   }  
   return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));  
}

大致邏輯如下:

  1. transformedBeanName 的作用是不管傳入的參數(shù)是 &××× 還是 ×××,都返回 ×××。這是因?yàn)镾pring標(biāo)記 FactoryBean 時(shí)使用 &××× 作為 FactoryBeanbeanName。
  2. getSingleton 方法從單例池中獲取 Bean 實(shí)例,如果該實(shí)例是 FactoryBean,則直接返回該實(shí)例。
  3. 如果 BeanFactory 中的 Bean 定義 Map 中不包含該 beanNameBean 定義,并且當(dāng)前 BeanFactory 的父 BeanFactory 實(shí)現(xiàn)了 ConfigurableBeanFactory 接口,那么就需要查看當(dāng)前父 BeanFactory 中是否有該實(shí)例,并且判斷該實(shí)例是否為 FactoryBean。舉個(gè)例子來說:
// 創(chuàng)建一個(gè)父Spring容器  
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();  
parent.register(AppConfig.class);  
parent.refresh();  
// 創(chuàng)建一個(gè)Spring容器  
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();  
applicationContext.setParent(parent);  
applicationContext.register(AppConfig1.class);  
applicationContext.refresh();  
UserService bean = applicationContext.getBean(UserService.class);  
bean.test();
  1. 如果并沒有實(shí)例化出來的bean,那么對bean定義進(jìn)行判斷。
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {  
   Boolean result = mbd.isFactoryBean;  
   if (result == null) {  
      // 根據(jù)BeanDefinition推測Bean類型(獲取BeanDefinition的beanClass屬性)  
  Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);  
      // 判斷是不是實(shí)現(xiàn)了FactoryBean接口  
  result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));  
      mbd.isFactoryBean = result;  
   }  
   return result;  
}

注釋也基本寫好了,基本上就是根據(jù)BeanDefinition推測Bean類型(獲取BeanDefinition的beanClass屬性),再根據(jù)bean類型判斷是不是實(shí)現(xiàn)了FactoryBean接口,然后返回判斷結(jié)果。

SmartFactoryBean

getBean 方法中,我們可以獲取 FactoryBean 的實(shí)例并返回。接下來的步驟是判斷當(dāng)前的 FactoryBean 是否實(shí)現(xiàn)了 SmartFactoryBean 接口。需要注意的是,SmartFactoryBeanFactoryBean 接口的一個(gè)子接口。雖然我們在實(shí)現(xiàn) FactoryBean 接口時(shí)不必實(shí)現(xiàn) SmartFactoryBean 接口,但是如果實(shí)現(xiàn)了 SmartFactoryBean 接口,那么在創(chuàng)建 FactoryBean 時(shí)就會(huì)調(diào)用 getObject 方法返回實(shí)例。正常情況下,只有當(dāng)容器啟動(dòng)完成后才會(huì)調(diào)用 getObject 方法。如果我們想在初始化時(shí)就調(diào)用,可以這樣實(shí)現(xiàn):

@Component  
public class UserFactory implements SmartFactoryBean {  
 
   @Override  
  public Object getObject() throws Exception {  
      return new User();  
   }  
  
   @Override  
  public Class<?> getObjectType() {  
      return User.class;  
   }  
  
   @Override  
  public boolean isEagerInit() {  
      return true;  
   }  
}

結(jié)語

FactoryBean 和 BeanFactory 是兩個(gè)不同的概念。前者是一個(gè)接口,我們可以在實(shí)現(xiàn)該接口時(shí)通過調(diào)用 getObject 方法來返回實(shí)例,同時(shí) FactoryBean 本身也是一個(gè)實(shí)例。后者是 Spring 容器的工廠,通過其中的 bean 定義 Map 一個(gè)一個(gè)地實(shí)例化我們通過注解等方式注入進(jìn)去的 bean 工廠。在判斷 FactoryBean 時(shí),如果當(dāng)前 BeanFactory 中沒有對應(yīng)的 bean 定義,那么就會(huì)去父容器中尋找相應(yīng)的 bean 定義并進(jìn)行判斷。如果我們的類實(shí)現(xiàn)了 SmartFactoryBean 接口,那么它將會(huì)在 Spring 容器啟動(dòng)時(shí)就會(huì)調(diào)用 getObject 方法創(chuàng)建實(shí)例。接下來,我們將分幾個(gè)小節(jié)來講解 getBean 方法是如何實(shí)例化 bean 的,因?yàn)槠^長會(huì)影響讀者的注意力和學(xué)習(xí)效果。文章來源地址http://www.zghlxwxcb.cn/news/detail-431046.html

到了這里,關(guān)于Spring源碼:Bean的生命周期(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring源碼:bean的生命周期(一)

    Spring源碼:bean的生命周期(一)

    本節(jié)將正式介紹Spring源碼細(xì)節(jié),將講解Bean生命周期。請注意,雖然我們不希望過于繁瑣地理解Spring源碼,但也不要認(rèn)為Spring源碼很簡單。在本節(jié)中,我們將主要講解Spring 5.3.10版本的源代碼。如果您看到的代碼與我講解的不同,也沒有關(guān)系,因?yàn)槠渲械脑砗蜆I(yè)務(wù)邏輯基本相

    2024年02月02日
    瀏覽(23)
  • 【Spring源碼】講講Bean的生命周期

    【Spring源碼】講講Bean的生命周期

    面試官:“看過Spring源碼吧,簡單說說Spring中Bean的生命周期” 大神仙:“基本生命周期會(huì)經(jīng)歷實(shí)例化 - 屬性賦值 - 初始化 - 銷毀”。 面試官:“......” 如果是普通Bean的生命周期,那么上述的回答是真正確的。確實(shí)會(huì)經(jīng)歷“實(shí)例化 - 屬性賦值 - 初始化 - 銷毀”四個(gè)階段。但

    2023年04月09日
    瀏覽(20)
  • 【Spring】Spring之Bean生命周期源碼解析

    什么是bean的生命周期 是指bean在spring中是如何生成,如何銷毀的; spring創(chuàng)建對象的過程,就是IOC(控制反轉(zhuǎn))的過程; JFR Java Flight Record,java飛行記錄,類似于飛機(jī)的黑匣子,是JVM內(nèi)置的基于事件的JDK監(jiān)控記錄框架,主要用于問題定位和持續(xù)監(jiān)控; 入口代碼: Spring啟動(dòng)的時(shí)

    2024年02月15日
    瀏覽(23)
  • 【框架源碼】Spring源碼解析之Bean生命周期流程

    【框架源碼】Spring源碼解析之Bean生命周期流程

    觀看本文前,我們先思考一個(gè)問題,什么是Spring的bean的生命周期?這也是我們在面試的時(shí)候,面試官常問的一個(gè)問題。 在沒有Spring之前,我們創(chuàng)建對象的時(shí)候,采用new的方式,當(dāng)對象不在被使用的時(shí)候,由Java的垃圾回收機(jī)制回收。 而 Spring 中的對象是 bean,bean 和普通的 J

    2024年02月09日
    瀏覽(21)
  • 【深入Spring源碼解析:解密Bean的生命周期】

    Spring是Java企業(yè)級應(yīng)用開發(fā)領(lǐng)域的一顆明星,它提供了很多方便開發(fā)人員的工具和思想。在分布式系統(tǒng)中,Spring的分布式遠(yuǎn)程協(xié)作方案,比如REST、Web服務(wù)以及消息傳遞等,也是不可或缺的。 你知道嗎?在我們使用Spring時(shí),容器中存放的所有對象,在Spring啟動(dòng)的時(shí)候就完成了實(shí)

    2024年02月05日
    瀏覽(28)
  • 【Spring專題】Spring之Bean的生命周期源碼解析——上(掃描生成BeanDefinition)

    【Spring專題】Spring之Bean的生命周期源碼解析——上(掃描生成BeanDefinition)

    由于Spring源碼分析是一個(gè)前后聯(lián)系比較強(qiáng)的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當(dāng)前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序): Spring底層核心原理解析——引導(dǎo)篇【學(xué)習(xí)難度: ★★☆☆☆ 】

    2024年02月13日
    瀏覽(22)
  • 【Spring專題】Spring之Bean的生命周期源碼解析——階段一(掃描生成BeanDefinition)

    【Spring專題】Spring之Bean的生命周期源碼解析——階段一(掃描生成BeanDefinition)

    由于Spring源碼分析是一個(gè)前后聯(lián)系比較強(qiáng)的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當(dāng)前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序): Spring底層核心原理解析——引導(dǎo)篇【學(xué)習(xí)難度: ★★☆☆☆ 】

    2024年02月13日
    瀏覽(24)
  • 【Spring專題】Spring之Bean的生命周期源碼解析——階段二(IOC之實(shí)例化)

    【Spring專題】Spring之Bean的生命周期源碼解析——階段二(IOC之實(shí)例化)

    由于Spring源碼分析是一個(gè)前后聯(lián)系比較強(qiáng)的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當(dāng)前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序): Spring底層核心原理解析——引導(dǎo)篇【學(xué)習(xí)難度: ★★☆☆☆ 】

    2024年02月13日
    瀏覽(37)
  • 【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入)

    【Spring專題】Spring之Bean的生命周期源碼解析——階段二(二)(IOC之屬性填充/依賴注入)

    由于Spring源碼分析是一個(gè)前后聯(lián)系比較強(qiáng)的過程,而且這邊分析,也是按照代碼順序講解的,所以不了解前置知識的情況下,大概率沒辦法看懂當(dāng)前的內(nèi)容。所以,特別推薦看看我前面的文章(自上而下次序): Spring底層核心原理解析【學(xué)習(xí)難度: ★★☆☆☆ 】 手寫簡易

    2024年02月12日
    瀏覽(25)
  • bean的生命周期(最全最細(xì)講解)

    bean的生命周期(最全最細(xì)講解)

    其定義為: 從對象的創(chuàng)建到銷毀的過程。 而Spring中的一個(gè)Bean從開始到結(jié)束經(jīng)歷很多過程,但總體可以分為 六個(gè)階段Bean定義、實(shí)例化、屬性賦值、初始化、生存期、銷毀 。 1.首先我們來創(chuàng)建一個(gè)包,在包中創(chuàng)建一個(gè)Orders的對象,然后在對象中創(chuàng)建一個(gè)無參構(gòu)造方法.... 2.Sp

    2023年04月22日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包