亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringIOC?BeanDefinition的加載流程詳解

 更新時間:2022年10月24日 10:15:00   作者:AntBlack  
這篇文章主要為大家介紹了SpringIOC?BeanDefinition的加載流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一.前言

這一篇來看看 SpringIOC 里面的一個細(xì)節(jié)點 , 來簡單看看 BeanDefinition 這個對象 , 以及有沒有辦法對其進(jìn)行定制.

CASE 備份 : ?? gitee.com/antblack/ca…

二. BeanDefinition 的體系

2.1 體系概覽

這里面需要關(guān)注的幾個類分別為 :

  • BeanDefinition 接口 : 頂層接口 , 抽象了Bean加載的方法
  • AbstractBeanDefinition : 提供了多數(shù)方法的默認(rèn)實現(xiàn)
  • RootBeanDefinition : Spring BeanFactory 運(yùn)行時統(tǒng)一的 BeanDefinition 視圖
  • GenericBeanDefinition : 編程方式注冊 BeanDefinition 的首選類
  • ChildBeanDefinition : 可繼承BeanDefinition

下面來解釋一下這里面說的一些概念 :

什么叫統(tǒng)一視圖 ?

稍微從跟蹤一下源碼就能發(fā)現(xiàn) , 從 xml 或者 JavaConfig 以及 Spring 默認(rèn)加載的Bean配置類 ,最終都會被修飾為 RootBeanDefinition

GenericBeanDefinition 怎么用 ?

GenericBeanDefinition 是通過編程方式注入的 BeanDefinition 所對應(yīng)的類 ,通常都是該類的子類 , 包括非Spring 的 ConfigBean 和 ServiceBean

ChildBeanDefinition 又做了什么 ?

一種可以繼承 parent 配置的 BeanDefinition , 在加載環(huán)節(jié)中會通過 AbstractBeanFactory#getMergedLocalBeanDefinition() 來將 child 和 parent bean definition 進(jìn)行合并。

  • BeanDefinition 進(jìn)行 merge 操作時,會將 child 的屬性與 parent 的屬性進(jìn)行合并,當(dāng)有相同屬性時,以 child 的為準(zhǔn)
  • 如果是 Map 形式的配置 , 會取并集

2.2 BeanDefinition 的作用

  • 存儲屬性 : 基于接口 AttributeAccessor 實現(xiàn)
  • 存儲元數(shù)據(jù)配置 : 基于 BeanMetadataElement 實現(xiàn)
  • 描述類的信息 : 包括Bean名稱 , Primary 屬性 , priority 配置 等等
  • Bean 的加載 : 例如 getBeansOfType , getBean 等等

總結(jié)其實就是一句話 : BeanDefinition 主要承載了Bean的元數(shù)據(jù)信息 ,同時描述了Bean在Spring體系中的加載方式 , 容器通過 BeanDefinition 中的配置來加載一個Bean

三. BeanDefinition 的載入

3.1 載入的入口

S1 : 啟動配置類的載入

Spring 中第一個載入的 BeanDefinition 即為 RootBeanDefinition , 主要通過 AnnotationConfigUtils # registerAnnotationConfigProcessors 方法進(jìn)行加載

在這個環(huán)節(jié)中會通過加載的方式分別載入多個不同的 RootBeanDefinition , 這里是 Contain 關(guān)系 :

// internalConfigurationAnnotationProcessor
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
   // 構(gòu)建對應(yīng)的 PostProcessor 并且載入
   RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
   def.setSource(source);
   beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// internalAutowiredAnnotationProcessor
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    //.....
}

在這個環(huán)節(jié)中 , 基本上都是在通過 registerPostProcessor 來注冊各類加載類 , 我把這些看成根類 .

這些類通常為 Spring 進(jìn)行服務(wù) , 用來配置各類信息和加載封裝 Bean

S2 : 普通配置類的載入

普通類的載入包括 SpringApplication 和一些自定義的個人配置類 , 這些類主要為了對非 Spring 的組件進(jìn)行注冊 , 配置 , 注入等操作

這一類通常通過 registerBean 來實現(xiàn)Bean的注冊 , 注冊的入口也很多 :

包括 AnnotatedBeanDefinitionReaderConfigurationClassPostProcessor等, 不難發(fā)現(xiàn)這一類 BeanDefinition 通常都是由 RootBeanDefinition 裝載的類進(jìn)行載入的

通常注冊出來的對象也為 AnnotatedGenericBeanDefinition 和 GenericBeanDefinition 的子類等

3.2 保存的邏輯

BeanDefinition 會在 DefaultListableBeanFactory # registerBeanDefinition 中進(jìn)行注冊.

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {
   // S1 : 會對 BeanDefinition 進(jìn)行校驗 , 主要是MethodOverrides和FactoryMethodName不能同時存在
   // -- 工廠方法必須創(chuàng)建具體的 Bean 實例 , 而 methodOverrides 會創(chuàng)建代理類且進(jìn)行增強(qiáng)
   // -- 也就是說 工廠需要實例 , 不能是代理類
   if (beanDefinition instanceof AbstractBeanDefinition) {
       ((AbstractBeanDefinition) beanDefinition).validate();
   }
   // S2 : 判斷 BeanDefinition 是否已經(jīng)存在
   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   if (existingDefinition != null) {
      // 是否允許同名Bean重寫 , 因為此處已經(jīng)存在一個了 , 不能重寫則直接異常 
      if (!isAllowBeanDefinitionOverriding()) {
         throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }else if (existingDefinition.getRole() < beanDefinition.getRole()) {
          // 角色比較 ,只打日志 
          // ROLE_APPLICATION / ROLE_SUPPORT / ROLE_INFRASTRUCTURE
      }else if (!beanDefinition.equals(existingDefinition)) {
          // 判斷是否為同一對象
      }
      // 以上主要是打log , 這里如果允許覆蓋則直接覆蓋了
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      // 判斷該Bean是否已經(jīng)開始初始化
      if (hasBeanCreationStarted()) {
         // 如果已經(jīng)開始 , 需要對 Map 上鎖后再處理
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            // 省略一些更新操作
         }
      }
      else {
         // 沒有加載時的載入
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }
   // 如果Bean已經(jīng)存在或已經(jīng)開始加載了 , 這個時候時需要進(jìn)行銷毀操作的
   if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}
protected void resetBeanDefinition(String beanName) {
   // S1 : 如果已經(jīng)創(chuàng)建 ,需要清空 Merge BeanDefinition
   clearMergedBeanDefinition(beanName);
   // S2 : 銷毀 Bean
   destroySingleton(beanName);
   // S3 : 調(diào)用 PostProcessors 重置處理器進(jìn)行處理
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      if (processor instanceof MergedBeanDefinitionPostProcessor) {
         ((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);
      }
   }
   // S4 : 如果該 BeanDefinition 是某個BeanDefinition 的Parent , 則需要同步處理
   for (String bdName : this.beanDefinitionNames) {
      if (!beanName.equals(bdName)) {
         BeanDefinition bd = this.beanDefinitionMap.get(bdName);
         if (bd != null && beanName.equals(bd.getParentName())) {
            resetBeanDefinition(bdName);
         }
      }
   }
}

3.3 使用的方式

BeanDefinition 的批量處理流程也是在 DefaultListableBeanFactory 中進(jìn)行的

public void preInstantiateSingletons() throws BeansException {
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
   // 對所有的 BeanDefinition 進(jìn)行循環(huán)處理
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      // 排除掉懶加載的Bean
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         // 此處省略工廠類的判斷及處理 ...
         // 進(jìn)入Bean獲取邏輯
         getBean(beanName);
      }
   }
    //.....
}

總結(jié)

分析 BeanDefinition 不是這階段的主要目的 , 后續(xù)會有幾篇應(yīng)用的文章來著重思考下如何進(jìn)行業(yè)務(wù)定制

其實寫源碼文章是最輕松的 , 看懂就完事了 , 而寫定制或者業(yè)務(wù) , 往往寫著寫著發(fā)現(xiàn)有地方?jīng)]搞懂 , 就需要回頭繼續(xù)看這個點 , 難度要大得多.......

附錄 : BeanDefinition 功能一覽

以上就是SpringIOC BeanDefinition的加載流程詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringIOC BeanDefinition加載的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java編程實現(xiàn)驗證哥德巴赫猜想

    Java編程實現(xiàn)驗證哥德巴赫猜想

    這篇文章主要介紹了Java編程實現(xiàn)驗證哥德巴赫猜想,具有一定參考價值,需要的朋友可以了解下。
    2017-12-12
  • Springsecurity Oauth2如何設(shè)置token的過期時間

    Springsecurity Oauth2如何設(shè)置token的過期時間

    如果用戶在指定的時間內(nèi)有操作就給token延長有限期,否則到期后自動過期,如何設(shè)置token的過期時間,本文就來詳細(xì)的介紹一下
    2021-08-08
  • SpringBoot關(guān)于自動注入mapper為空的坑及解決

    SpringBoot關(guān)于自動注入mapper為空的坑及解決

    這篇文章主要介紹了SpringBoot關(guān)于自動注入mapper為空的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法

    Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法

    Java中可以通過Thread類和Runnable接口來創(chuàng)建多個線程,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • Netty的Handler鏈調(diào)用機(jī)制及如何組織詳解

    Netty的Handler鏈調(diào)用機(jī)制及如何組織詳解

    這篇文章主要為大家介紹了Netty的Handler鏈調(diào)用機(jī)制及如何組織示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 使用Feign擴(kuò)展包實現(xiàn)微服務(wù)間文件上傳

    使用Feign擴(kuò)展包實現(xiàn)微服務(wù)間文件上傳

    這篇文章主要為大家詳細(xì)介紹了使用Feign擴(kuò)展包實現(xiàn)微服務(wù)間文件上傳,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • 使用Idea maven創(chuàng)建Spring項目過程圖解

    使用Idea maven創(chuàng)建Spring項目過程圖解

    這篇文章主要介紹了使用Idea maven創(chuàng)建Spring項目過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • Java中的自旋鎖spinlock詳解

    Java中的自旋鎖spinlock詳解

    這篇文章主要介紹了Java中的自旋鎖spinlock詳解,自旋鎖就是循環(huán)嘗試獲取鎖,不會放棄CPU時間片,減傷cup上下文切換,缺點是循環(huán)會消耗cpu,需要的朋友可以參考下
    2024-01-01
  • java實現(xiàn)ArrayList根據(jù)存儲對象排序功能示例

    java實現(xiàn)ArrayList根據(jù)存儲對象排序功能示例

    這篇文章主要介紹了java實現(xiàn)ArrayList根據(jù)存儲對象排序功能,結(jié)合實例形式分析了java針對ArrayList的相關(guān)運(yùn)算、排序操作技巧,需要的朋友可以參考下
    2018-01-01
  • JSqlParse完整介紹

    JSqlParse完整介紹

    JSqlParse是一款很精簡的sql解析工具,本文主要介紹了JSqlParse完整介紹,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05

最新評論