從0-1了解Spring是如何運行起來的(四):BeanFactory后處理初分析,了解如何加載BeanDefinition

前言

最深刻了解一個框架的思想的方式,莫過于看源碼,本系列旨在于從Springboot底層源碼(Version - 2.6.6)出發(fā),一步步了解springboot是如何運行起來的。

從0-1了解SpringBoot如何運行(一):Environment環(huán)境裝配

從0-1了解SpringBoot是如何運行起來的(二):定制你的banner

從0-1了解Spring是如何運行起來的(三):Context預(yù)處理,為加載容器做準(zhǔn)備

在前述的文章中,我們主要了解了SpringBoot是如何實現(xiàn)配置文件的加載、context的創(chuàng)建、banner圖打印的流程。這次的話我們主要針對context中的refresh處理進(jìn)行學(xué)習(xí)和解析。

public ConfigurableApplicationContext run(String... args) {
    ......
    refreshContext(context);
    ......
}

簡介

本章節(jié)我們主要針對BeanDefinition的加載以及BeanFactory后處理進(jìn)行學(xué)習(xí)。在展開講解源碼之前,我們需要先來了解一下這些概念。

BeanDefinition

BeanDefinition是一個描述 Bean的類實例,其其實是一個描述bean和修改bean信息的一個接口對象。如下是BeanDefinition的一個繼承類圖:

BeanDefinition

從類圖中可以看到,其繼承了BeanMetaDataElementAttributeAccessor。前者是Bean的元數(shù)據(jù)的存儲對象,其source屬性保存的是Bean實例的最基礎(chǔ)的定義信息。而AttributeAccessor則是提供了對BeanDefinition的一些操作接口,包括獲取特定的屬性、移除特定屬性以及添加特定屬性的方法。

BeanDefinition在Spring中其實是一個相當(dāng)重要的概念。其就如同Bean對象的圖紙,需要生產(chǎn)什么樣子的Bean都由BeanDefinition來定義。 同時結(jié)合類圖來看,我們不難看到,BeanDefinition還有以下的一些能力:

  • 標(biāo)記當(dāng)前的Bean的作用范圍;
  • 定義當(dāng)前Bean的工廠Bean的名稱;
  • 當(dāng)前Bean的初始化方法名稱;
  • 當(dāng)前Bean是否支持懶加載
  • ... ...

通過對BeanDefinition進(jìn)行加載并存儲到BeanDefinitionMap中,后續(xù)Spring才能依照這些對應(yīng)的“圖紙”生成出匹配的Bean實例對象。

BeanFactoryPostProcessor

BeanFactoryPostProcessor實際是用來處理BeanFactory的后置處理器。其生效的主要時間段是在Bean實例化之前。另外,BeanFactoryPostProcessor其實也是Spirng提供的一個鉤子,其可以讓你根據(jù)自己的實際情況修改Bean的定義屬性。 最常見的應(yīng)用就是我們的Bean中會有一些占位符,那么在Bean實例化之前這些占位符肯定是要被實際的配置參數(shù)填充的,這個填充的過程就是通過BeanFactoryPostProcessor的后置處理完成的。

源碼解析:

在了解了上述的基本內(nèi)容后,我們就可以從源碼角度對整個bean的加載過程進(jìn)行了解和分析了。

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
      // 對刷新做了一些初始化的設(shè)置 
       prepareRefresh();
      // 更新對工廠的引用 并 獲取容器工廠
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // 預(yù)先對BeanFactory進(jìn)行相應(yīng)的處理,如設(shè)置上下文的類加載器、默認(rèn)的Bean等
      prepareBeanFactory(beanFactory);
      try {
         // 抽象類預(yù)留的hook方法,允許子類在標(biāo)準(zhǔn)的BeanFactory初始化后,再進(jìn)行初始化。(模版設(shè)計模式)
         postProcessBeanFactory(beanFactory);
         StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
         //關(guān)鍵代碼:會在這里調(diào)用BeanFactory的后處理器來初始化BeanDefinition,BD會在這里被加載到BDMap中。
         invokeBeanFactoryPostProcessors(beanFactory);
        ......
      }catch (BeansException ex) {
        ...
      }finally {
        ...
      }
   }
}

Refresh(代碼的整體結(jié)構(gòu)采用模版設(shè)計模式實現(xiàn),具體的實現(xiàn)由子類實現(xiàn)。由于Refresh部分的整體的代碼塊相對較長,且包含的內(nèi)容較多。因此,本期我們只針對invokeBeanFactoryPostProcessors()及其之前的代碼進(jìn)行查看。可以看到,在執(zhí)行invokeBeanFactoryPostProcessors()之前,Spring對相應(yīng)的工廠做了一些處理,主要包括

1、發(fā)送context刷新的事件;

2、更新工廠的引用數(shù)據(jù)

3、預(yù)處理工廠數(shù)據(jù),如設(shè)置累加載器,注入一些默認(rèn)的BeanDefinition等。

4、如果這里我們實現(xiàn)了預(yù)留的postProcessBeanFactory方法,那么還會執(zhí)行這個模版鉤子。

5、再次發(fā)送Bean初始化的事件

6、調(diào)用BeanFactory的后處理器。

這里我們跳過前面的幾個步驟,直接追入最關(guān)鍵的源代碼進(jìn)行查看:

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory,              List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
   Set<String> processedBeans = new HashSet<>();
    // 判斷當(dāng)前是否為BeanDef注冊器
   if (beanFactory instanceof BeanDefinitionRegistry) {
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
      List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
      for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
         if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
            BeanDefinitionRegistryPostProcessor registryProcessor =
                  (BeanDefinitionRegistryPostProcessor) postProcessor;
            registryProcessor.postProcessBeanDefinitionRegistry(registry);
            registryProcessors.add(registryProcessor);
         }else {
            regularPostProcessors.add(postProcessor);
         }
      }
       //加載第一批次的BeanFactoryPostProcessor,并進(jìn)行調(diào)用(該批次的均實現(xiàn)了PriOrityOrdered.class類)
      List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
      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);
       //此處調(diào)用第一批次的BDF注冊處理器。(如configClassPostProcessor,作用是加載所有的ConfigClass的BeanDef)
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
      currentRegistryProcessors.clear();

       //調(diào)用第二批次的BDF處理器(此處代碼中什么都沒做。。。因為沒有實現(xiàn)ordered的類 O。O)
      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, beanFactory.getApplicationStartup());
      currentRegistryProcessors.clear();
        //循環(huán)對第三批次的BDF處理器進(jìn)行調(diào)用,直到無處理器,這里主要是對尚未初始化的BD進(jìn)行占位符等信息的替換填充,
        //eg. MapperScannerConfigurer會對mapper的基礎(chǔ)包路徑、作用域范圍進(jìn)行占位符的填充。
      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, beanFactory.getApplicationStartup());
         currentRegistryProcessors.clear();
      }
      invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
   }else {
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
   }
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
        //按照實現(xiàn)了PriorityOrder、Ordered和其余的分類方式將處理器分開
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        List<String> orderedPostProcessorNames = new ArrayList<>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // 如果已經(jīng)處理,則跳過
            }else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            }else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

    // 首先,再次調(diào)用實現(xiàn)了priorityOrdered的Processor。
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    
   // 接下來再調(diào)用一次實現(xiàn)了ordered的Processor。
   List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
   for (String postProcessorName : orderedPostProcessorNames) {
      orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
   // 最后調(diào)用所有其他的后處理器
   List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
   for (String postProcessorName : nonOrderedPostProcessorNames) {
      nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
   // 清除掉所有的緩存數(shù)據(jù)信息
   beanFactory.clearMetadataCache();
}

這部分的源碼其實較長,整塊代碼主要是針對于BeanFactoryPostProcessor的執(zhí)行進(jìn)行操作的。這里梳理了一下整塊代碼的執(zhí)行邏輯:

第一階段:加載完BD前,調(diào)用初始化前的BeanFactoryPostProcessor:

  1. 調(diào)用實現(xiàn)了PriorityOrder的BeanFactoryPostProcessor類。(如ConfigurationClassPostProcessor,負(fù)責(zé)加載beanFactory內(nèi)的BeanDef)
  2. 調(diào)用實現(xiàn)了Ordered的BeanFactoryPostProcessor類。
  3. 執(zhí)行剩余的所有BeanFactoryPostProcessor類。(如MapperScannerConfigure,對mapper的基本包路徑、是否懶加載等進(jìn)行占位符替換。)

第二階段: 加載完BD后,調(diào)用非提前初始化的 BeanFactoryPostProcessor:

  1. 調(diào)用實現(xiàn)了PriorityOrder的BeanFactoryPostProcessor類。(如PropertySourcesPlaceholderConfigurer,對所有的BeanDef的占位符進(jìn)行填充)

  2. 調(diào)用實現(xiàn)了Ordered的BeanFactoryPostProcessor類。(如DependsOnDatabaseInitializationPostProcessor,控制DB的依賴屬性)

  3. 執(zhí)行剩余的所有BeanFactoryPostProcessor類。

首先,根據(jù)整個加載流程,可以比較直觀的一點是,對于BeanFactory的處理,我們在某種程度上是可以控制其PostProcessor加載調(diào)用的先后順序,這個可以通過PriorityOrder、Ordered等注解進(jìn)行相應(yīng)的控制。

接著,我們主要對上述的BeanFactoryPostProcessor中比較重要的兩個處理器進(jìn)行展開分析和學(xué)習(xí):

ConfigurationClassPostProcessor

`org.springframework.context.annotation.ConfigurationClassPostProcessor`主要實現(xiàn)的功能是將各處的配置類及其對應(yīng)的Bean的BeanDefinition掃描到對應(yīng)的Factory 中。其執(zhí)行的地方在第一階段,加載的主要源代碼如下所示:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
   List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
   String[] candidateNames = registry.getBeanDefinitionNames();
   //獲取此時的候選BeanDef的名字
   for (String beanName : candidateNames) {
      BeanDefinition beanDef = registry.getBeanDefinition(beanName);
      if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
         if (logger.isDebugEnabled()) {
            logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
         }
      } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
   }
   // 如果當(dāng)前沒有需要加載的配置類,則直接返回
   if (configCandidates.isEmpty()) {
      return;
   }
   // 根據(jù)對應(yīng)的@Order注解的值排序?qū)?yīng)的配置候選類
   configCandidates.sort((bd1, bd2) -> {
      int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
      int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
      return Integer.compare(i1, i2);
   });
   // 通過應(yīng)用上下文來檢測所有的自定義bean名稱的生成策略。
   SingletonBeanRegistry sbr = null;
   if (registry instanceof SingletonBeanRegistry) {
      sbr = (SingletonBeanRegistry) registry;
      if (!this.localBeanNameGeneratorSet) {
         BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
               AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
         if (generator != null) {
            this.componentScanBeanNameGenerator = generator;
            this.importBeanNameGenerator = generator;
         }
      }
   }
    //如果環(huán)境配置為null,則生成一個標(biāo)準(zhǔn)的環(huán)境
   if (this.environment == null) {
      this.environment = new StandardEnvironment();
   }
   // 生成一個配置類解析器
   ConfigurationClassParser parser = new ConfigurationClassParser(
         this.metadataReaderFactory, this.problemReporter, this.environment,
         this.resourceLoader, this.componentScanBeanNameGenerator, registry);
   Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
   Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
   do {
      StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
      parser.parse(candidates); // 對配置的候選類進(jìn)行解析,直到所有的配置類被解析完成,退出循環(huán)
      parser.validate();
      Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
      configClasses.removeAll(alreadyParsed);
      // 創(chuàng)建配置類BeanDefinition閱讀器
      if (this.reader == null) {
         this.reader = new ConfigurationClassBeanDefinitionReader(
               registry, this.sourceExtractor, this.resourceLoader, this.environment,
               this.importBeanNameGenerator, parser.getImportRegistry());
      }
      //加載配置類BD
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);
      processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
      candidates.clear(); // 清空候選配置類
      if (registry.getBeanDefinitionCount() > candidateNames.length) {
         String[] newCandidateNames = registry.getBeanDefinitionNames();
         Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
         Set<String> alreadyParsedClasses = new HashSet<>();
         for (ConfigurationClass configurationClass : alreadyParsed) {
            alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
         }
         for (String candidateName : newCandidateNames) {
            if (!oldCandidateNames.contains(candidateName)) {
               BeanDefinition bd = registry.getBeanDefinition(candidateName);
               if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                     !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                  candidates.add(new BeanDefinitionHolder(bd, candidateName));
               }
            }
         }
         candidateNames = newCandidateNames;
      }
   }
   while (!candidates.isEmpty());
   if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
      sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
   }
   if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
      ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
   }
}

上述源代碼的主要工作流程如下所示:

1、因為整個類的主要功能其實是對配置的類進(jìn)行加載,那么首先肯定要獲取到哪些是我們當(dāng)前需要加載的類,即找到configCandidates(翻譯為:候選的配置)

2、因為Spring本身加載配置類,也是需要一個先后順序的,那么此時需要先根據(jù)@Order的方式來進(jìn)行排序。

3、因為beanDefinition本身的名字都是由BeanNameGenerator生成的,那么這時肯定需要找到哪個才是我們需要調(diào)用的Bean的名字的生成器,從而進(jìn)行后續(xù)BeanDef的名字的生成

4、實例化一個 ConfigurationClassParser ,從名字猜測,就是專門解析我們的配置類的,然后執(zhí)行parser.parse(candidates);對候選配置類進(jìn)行解析,在一開始的時候,beanDefinition里面除了那些約定的類,其實只有我們自己的啟動類了,而我們的啟動類也是有@Configuration的,所以一開始其實就是解析我們的啟動類。在解析我們的啟動類的時候,不難想象,application類底下肯定還是有許多依賴的類的(通常通過@ComponentScan掃描出來),那么自然也是需要對這些類進(jìn)行加載的。這里我簡單的畫了一下不同配置類之間的依賴關(guān)系:

其實一看就是一顆典型的多叉樹,那么對于多叉樹的遍歷,腦海中不由自主的其實會想到?;蜻f歸。實際上,Spring也是如此做的。這個流程的大致加載邏輯如下圖所示:

執(zhí)行完了`parser.parse(candidates);`,其實只是將Config類的BeanDefinition給加載了,但是其中可能還有其管理的Bean實例可能都還是沒有加載進(jìn)來的的,那么此時就需要執(zhí)行一次`this.reader.loadBeanDefinitions(configClasses);`對配置類管理的相關(guān)Bean進(jìn)行加載。

在解析啟動類之后,將解析出來的所有類再次減去已經(jīng)解析的類,就會得到下一批需要解析的啟動類,依次循環(huán)往返,直到解析完所有的類,那么此時加載就算完成了。

5、在加載完了所有的BeanDef后,會將元信息讀取工廠的緩存清除了。由此以來,整個配置類及其依賴的BeanDef的加載流程就宣告結(jié)束。

PropertySourcesPlaceholderConfigurer

對于beanDef內(nèi)占位符的替換,主要由*PropertySourcesPlaceholderConfigurer*實現(xiàn)。其主要的處理步驟如下所示:

1、依據(jù)當(dāng)前工廠的不同environment創(chuàng)建不同的propertyResolver。

2、對不同的propertyResolver設(shè)置占位符的前綴(prefix)、后綴(suffix)、以及變量的切分符(valueSeparator)。一般默認(rèn)會是"${"、"}"和":"

3、根據(jù)propertyResolver再創(chuàng)建出BeanDefinitionVisitor,用于對不同的bean進(jìn)行遍歷及變量替換。

替換變量邏輯中的關(guān)鍵的核心代碼如下所示:

protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
      StringValueResolver valueResolver) {
   BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
    //獲取到所有已經(jīng)加載好的Bd
   String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
   for (String curName : beanNames) {
      // 首先判斷不是處理“自己”對應(yīng)的BD才會進(jìn)行處理
      if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
         BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
         try {
             //關(guān)鍵代碼
            visitor.visitBeanDefinition(bd);
         }
         catch (Exception ex) {
            throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
         }
      }
   }
    //在Spring2.5中會對Alias(同名屬性)也進(jìn)行更新
   beanFactoryToProcess.resolveAliases(valueResolver);
   //會將屬性值的處理器保存下來
   beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}

執(zhí)行前:

執(zhí)行后:

總結(jié)

相比前幾章,本章從內(nèi)容來說,是Spring中相對關(guān)鍵關(guān)鍵的內(nèi)容,主要描述的是關(guān)于BeanDef的加載、BeanDef內(nèi)占位符的數(shù)據(jù)填充等。最后讓我們回過頭來,再次審視一次整個refresh()代碼執(zhí)行的邏輯流程:

1、發(fā)送context刷新的事件;

2、更新工廠的引用數(shù)據(jù);

3、預(yù)處理工廠數(shù)據(jù),如設(shè)置類加載器,注入一些默認(rèn)的BeanDefinition等。

4、如果這里我們實現(xiàn)了預(yù)留的postProcessBeanFactory方法,那么還會執(zhí)行這個模版鉤子。

5、再次發(fā)送Bean初始化的事件

6、調(diào)用BeanFactory的后處理器。

  • 第一階段:加載完BD前,調(diào)用初始化前的BeanFactoryPostProcessor:

    1. 調(diào)用實現(xiàn)了PriorityOrder的BeanFactoryPostProcessor類。(如ConfigurationClassPostProcessor,負(fù)責(zé)加載beanFactory內(nèi)的BeanDef)
    2. 調(diào)用實現(xiàn)了Ordered的BeanFactoryPostProcessor類。
    3. 執(zhí)行剩余的所有BeanFactoryPostProcessor類。(如MapperScannerConfigure,對mapper的基本包路徑、是否懶加載等進(jìn)行占位符替換。)
  • 第二階段: 加載完BD后,調(diào)用非提前初始化的 BeanFactoryPostProcessor:

    1. 調(diào)用實現(xiàn)了PriorityOrder的BeanFactoryPostProcessor類。(如PropertySourcesPlaceholderConfigurer,對所有的BeanDef的占位符進(jìn)行填充)

    2. 調(diào)用實現(xiàn)了Ordered的BeanFactoryPostProcessor類。(如DependsOnDatabaseInitializationPostProcessor,控制DB的依賴屬性)

    3. 執(zhí)行剩余的所有BeanFactoryPostProcessor類。

歸納成流程圖,整個流程就可以描述成如下的形式:

參考文章

Spring IOC 有什么好處呢

Spring(四)核心容器 - BeanDefinition 解析

Spring源碼-學(xué)習(xí)隨筆(三)springboot的類加載beanDefinition的過程簡述

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容