Spring Boot 啟動原始碼解析結合Spring Bean生命週期分析

香吧香發表於2022-05-03

轉載請註明出處:

 

1.SpringBoot 原始碼執行流程圖

 

2. 建立SpringApplication 應用,在建構函式中推斷啟動應用型別,並進行spring boot自動裝配

  public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

  檢視 SpringApplication 建構函式

  public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        // 獲取banner列印模式
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        // 新增命令列系統屬性
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = Collections.emptySet();
        this.isCustomEnvironment = false;
         // 是否懶載入
        this.lazyInitialization = false;
        // 預設賦值 applicationContextFactory 工廠物件
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
         // 根據類載入路徑推斷webApplicaitonType型別:SERVLET;REACTIVE
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 進行Spring的自動裝配,主要用來SpringFactoriesLoader類進行裝載工廠
        this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
         // 設定監聽器
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

  getSpringFactoriesInstances 方法主要用來進行Spring的自動裝配;用 SpringFactoriesLoader類 進行裝載工廠,工廠資源位於 META-INF/spring.factories 檔案中,這個檔案可能在類路徑的多個jar檔案中。然後呼叫createSpringFactoriesInstances() 方法對工廠進行例項化並根據註解進行排序。

3.SpringApplication.run方法原始碼

  檢視run方法原始碼

   public ConfigurableApplicationContext run(String... args) {
        // 應用啟動計時器
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        // 初始化應用上下文
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        // 獲取啟動監聽器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //監聽器使用類似於生產-消費模式進行訊息監聽
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            //構建應用引數
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //準備應用環境
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            //列印banner
            Banner printedBanner = this.printBanner(environment);
            //建立ApplicationContext
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            //準備context
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            //重點:重新整理context:實現IOC容器啟動的整個過程
            this.refreshContext(context);
            //後置工作
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }
        
    }

  獲取啟動監聽器。實際上獲取的是一個EventPublishingRunListener物件,這個類能通過一個SimpleApplicationEventMulticaster物件廣播事件,用到了Executor多執行緒非同步執行框架;

3.1 執行prepareEnvironment 方法,準備應用環境

  prepareEnvironment 方法原始碼

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
        // 根據前面推斷的web環境型別建立推Environment物件
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        // 進行環境配置
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach((Environment)environment);
        listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
        DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
        this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }

        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }

  prepareEnvironment 方法主要用來準備應用環境,進行property配置檔案解析,profile 環境解析以及獲取系統屬性和系統環境等;

3.1.1 getOrCreateEnvironment 方法原始碼

  private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        } else {
            switch(this.webApplicationType) {
            case SERVLET:
                return new StandardServletEnvironment();
            case REACTIVE:
                return new StandardReactiveWebEnvironment();
            default:
                return new StandardEnvironment();
            }
        }
    }

   StandardEnvironment的構造器會先對屬性源進行定製(將系統屬性和系統環境新增到一個MutablePropertySources維護的list中)。這個物件的主要工作包括property分析、profile相關操作、獲取系統屬性和系統環境等

3.1.2 configureEnvironment() 方法獲取配置環境

  configureEnvironment() 原始碼:

  protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            ConversionService conversionService = ApplicationConversionService.getSharedInstance();
            environment.setConversionService((ConfigurableConversionService)conversionService);
        }
        // 配置屬性源
        this.configurePropertySources(environment, args);
        //獲取啟用的 profile
        this.configureProfiles(environment, args);
    }

  configureProfiles 方法通過AbstractEnvironment#getActiveProfiles() 解析 spring.profile.active 屬性,新增到activeProfiles這個集合中。

3.2.createApplicationContext方法

  createApplicationContext 方法原始碼

  protected ConfigurableApplicationContext createApplicationContext() {
        return this.applicationContextFactory.create(this.webApplicationType);
    }

  進入 applicationContextFactory.create 方法的類中,存在一個根據webApplicationType獲取容器型別的變數方法如下:

@FunctionalInterface
public interface ApplicationContextFactory {
    // 根據webApplicationType返回指定的容器例項
    applicationContextFactoryApplicationContextFactory DEFAULT = (webApplicationType) -> {
        try {
            switch(webApplicationType) {
            case SERVLET:
                return new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            default:
                return new AnnotationConfigApplicationContext();
            }
        } catch (Exception var2) {
            throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
        }
    };
      ConfigurableApplicationContext create(WebApplicationType webApplicationType);
}

  通過以上方式獲取到具體的ApplicationContext例項,並通過建構函式進行例項化,檢視建構函式的過程:

3.2.1AnnotationConfigApplicationContext() 的構造方法  

  構造方法原始碼如下:

public AnnotationConfigApplicationContext() {
        // 啟動上面獲取的容器型別例項
        StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
        // 構建AnnotatedBeanDefinitionReader物件
        this.reader = new AnnotatedBeanDefinitionReader(this);
        createAnnotatedBeanDefReader.end();
          // 構建 ClassPathBeanDefinitionScanner物件
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

  AnnotationConfigApplicationContext的預設構造器會構造一個AnnotationBeanDefinitionReader物件和ClassPathBeanDefinitionScanner物件,在構造AnnotationBeanDefinitionReader物件的過程中會向bean factory新增註解處理器和事件監聽處理器BeanDefinition,為後續的配置解析作準備。這樣,就能通過JavaConfig 構建 BeanDefinition 並實現自動掃描。

  AnnotationConfigApplicationContext的父類GenericApplicationContext的預設構造器會構造一個DefaultListableBeanFactory 物件,這樣應用上下文持有一個bean factory的引用,大部分應用只需與應用上下文提供的介面打交道就是因為它對bean factory進行了一層封裝。至此,一個Spring容器已經構造出來了,但是目前這個容器還什麼都沒有,需要根據使用者的配置檔案進行配置才能按照使用者邏輯進行工作。

 

3.3.prepareContext方法

  prepareContext 方法原始碼

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        // 使context持有應用環境的引用,同時將應用環境的引用賦給reader和scanner
        context.setEnvironment(environment);
        // 實現應用上下文的後置處理:主要是註冊BeanNameGenerator型別的bean並設定應用上下文的資源載入器和類載入器
        this.postProcessApplicationContext(context);
        // 應用初始化器--新增監聽器、logger、warnning、以及spring啟動加解密等元件
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        bootstrapContext.close(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 新增啟動相關的bean
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        // 註冊列印banner的bean
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        // 註冊可定義重寫的bean
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 新增懶載入的bean工廠後置處理器
        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        // Load the sources
        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        // 重點:將source bean裝載到應用上下文
        this.load(context, sources.toArray(new Object[0]));
        // 日誌配置
        listeners.contextLoaded(context);
    }

  該方法主要進行 context 新增初始化器,包括監聽器、logger、warnning、以及spring啟動加解密元件等等;並設定一些啟動需要的 bean;

  通過 load 方法將所有的bean註冊到 容器中;該方法實現的呼叫鏈如下:

SpringApplication.load(ApplicationContext context, Object[] sources)-------->
BeanDefinitionLoader.load()---->BeanDefinitionLoader.load(Object source)--->
BeanDefinitionLoader.load(Class<?> source)----->AnnotatedBeanDefinitionReader.register(Class<?>... componentClasses)--->
AnnotatedBeanDefinitionReader.registerBean(Class<?> beanClass)---->
AnnotatedBeanDefinitionReader.doRegisterBean --->
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

  需要關注 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry) 這個操作;繼續跟進這個方法的具體實現,會發現所有的 bean 註冊都是儲存在一個map中,比如DefaultListableBeanFactory 類中的registerBeanDefinition 方法是將bean儲存到自定義的map集合中

private final Map<String, BeanDefinition> beanDefinitionMap;

 

3.4 refreshContext中refresh方法

  檢視refreshContext 中 refresh 方法原始碼

public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    // 為應用上下文的重新整理做準備--設定時間、記錄重新整理日誌、初始化屬性源中的佔位符和驗證必要的屬性等
    prepareRefresh();

    // Tell the subclass to refresh the internal bean factory.
    // 使用CAS讓子類重新整理內部的bean factory
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // Prepare the bean factory for use in this context.
    // 準備在這個應用上下文中使用的bean factory
    prepareBeanFactory(beanFactory);

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

      // Invoke factory processors registered as beans in the context.
      // 呼叫應用上下文中作為bean註冊的工廠處理器
      invokeBeanFactoryPostProcessors(beanFactory);

      // Register bean processors that intercept bean creation.
      // 註冊攔截建立bean的bean處理器
      registerBeanPostProcessors(beanFactory);

      // Initialize message source for this context.
      // 初始化訊息源
      initMessageSource();

      // Initialize event multicaster for this context.
      // 初始化事件廣播
      initApplicationEventMulticaster();

      // Initialize other special beans in specific context subclasses.
      // 初始化特定上下文子類中的其它bean
      onRefresh();

      // Check for listener beans and register them.
      // 註冊監聽器bean
      registerListeners();

      // Instantiate all remaining (non-lazy-init) singletons.
      // 例項化所有的單例bean
      finishBeanFactoryInitialization(beanFactory);

      // Last step: publish corresponding event.
      // 釋出相應的事件
      finishRefresh();
    }
    catch (BeansException ex) {
      if (logger.isWarnEnabled()) {
        logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
      }

      // Destroy already created singletons to avoid dangling resources.
      destroyBeans();

      // Reset 'active' flag.
      cancelRefresh(ex);

      // Propagate exception to caller.
      throw ex;
    }
    finally {
      // Reset common introspection caches in Spring's core, since we
      // might not ever need metadata for singleton beans anymore...
      resetCommonCaches();
    }
  }
}

  

3.4.1 prepareRefresh()

  AbstractApplicationContext#prepareRefresh() 原始碼:

protected void prepareRefresh() {
   //記錄啟動時間
   this.startupDate = System.currentTimeMillis();
   //標誌位設定
   this.closed.set(false);
   this.active.set(true);

   //日誌記錄一下
   if (logger.isInfoEnabled()) {
       logger.info("Refreshing " + this);
   }

   // Initialize any placeholder property sources in the context environment
   // 初始化資源佔位符
   initPropertySources();

   // Validate that all properties marked as required are resolvable
   // see ConfigurablePropertyResolver#setRequiredProperties
   // 驗證所有必要的屬效能通過getProperty()解析,不能則丟擲異常
   getEnvironment().validateRequiredProperties();

   // Allow for the collection of early ApplicationEvents,
   // to be published once the multicaster is available...
   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

  建立environment並載入System.properties()及System.getenv()到environment中

 

3.4.2 obtainFreshBeanFactory()

  因為AbstractApplication沒有引用bean factory,只定義了重新整理bean factory相關的方法,重新整理bean factory的具體實現在子類的GenericApplicationContext#refreshBeanFactory()中實現,具體程式碼和說明如下:

protected final void refreshBeanFactory() throws IllegalStateException {
   // 只支援重新整理一次
   if (!this.refreshed.compareAndSet(false, true)) {
       throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call  'refresh' once");
   }
   // 設定序列號
   this.beanFactory.setSerializationId(getId());
}

  可以看到對bean factory的重新整理實際上只是為其設定了一個序列號。

 

 

3.4.3 prepareBeanFactory()

   AbstractApplicationContext#prepareBeanFactory()。這個方法比較長,主要做的工作是對bean factory進行一些設定並新增一些輔助bean,具體程式碼和說明如下:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   // 使用應用上下文的類載入器
   beanFactory.setBeanClassLoader(getClassLoader());
   // 設定bean表示式解析器
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   // 新增屬性編輯器註冊器
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this,getEnvironment()));

   // Configure the bean factory with context callbacks.
   // 使用上下文回撥函式配置bean factory
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

   // BeanFactory interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   // 註冊依賴
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Register early post-processor for detecting inner beans as ApplicationListeners.
   // 新增一個用於探測實現了ApplicationListener介面的bean的後置處理器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   // 探測LoadTimeWeaver並準備織入,與AOP相關
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
       beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));

     // Set a temporary ClassLoader for type matching.
     beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   // 將預設環境作為bean註冊
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
       beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
       beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
       beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

  addBeanPostProcessor()會新增一個ApplicationContextAwareProcessor處理器,這個類實現了BeanPostProcessor介面,同時由於應用上下文持有其它*Aware等的引用,因此在後面的程式碼中忽略了這些依賴

3.4.4 invokeBeanFactoryPostProcessors()

  該方法會掃描到指定包下標有註解的類,然後將其變成BeanDefinition物件,然後放到一個Spring的Map中,用於後面建立Spring bean的時候使用這個BeanDefinition

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   // BeanFactory後置處理器的具體實現
   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

   // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
   // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
       beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
       beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
}

  

  Spring委託PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors實現後置處理,它的具體實現很長,系統啟動時就註冊了幾個後置處理器,如SharedMetadataReaderFactoryContextInitializer,CachingMetadataReaderFactoryPostProcessor等。

  程式碼的執行思路是:先將後置處理器進行分類,分別是BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,同時將BeanDefinitionRegistry註冊為一個BeanDefinition並呼叫登錄檔後置處理器的相關方法(與登錄檔相關);接著,按PriorityOrdered, Ordered和其它的順序呼叫手動新增(Spring Boot)的後置處理器。Spring Boot在之前註冊過一個ConfigurationClassPostProcessor後置處理器;

  最終這個後置處理器會呼叫ConfigurationClassPostProcessor#processConfigBeanDefinitions()對配置類進行處理。在處理時需要建立 ConfigurationClassParser物件進行解析,同時會建立一個 ComponentScanAnnotationParser 物件,在這個類中會掃描獲取所有帶有註解的bean類;

  ConfigurationClassPostProcessor#processConfigBeanDefinitions()具體的思路是先獲取所有的bean definition,並找出配置類對應的bean definition。接著對容器進行一下轉換並例項化一個ConfigurationClassParser配置類解析器物件parser,呼叫parser的parse()對配置類進行解析。ConfigurationClassParser#parse()的具體實現如下:

  

public void parse(Set<BeanDefinitionHolder> configCandidates) {
   this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();

   for (BeanDefinitionHolder holder : configCandidates) {
       BeanDefinition bd = holder.getBeanDefinition();
       try {
           //如果bean是註解的,則解析註解---Spring Boot基於註解配置
           if (bd instanceof AnnotatedBeanDefinition) {
               parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
           }
           // 如果是抽象bean並且有bean類
           else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
               parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
         } else {
            // 普通解析
           parse(bd.getBeanClassName(), holder.getBeanName());
         }
       }
       catch (BeanDefinitionStoreException ex) {
           throw ex;
     } catch (Throwable ex) {
         throw new BeanDefinitionStoreException(  "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
     }
   }
     // 處理延遲匯入的選擇器
     processDeferredImportSelectors();
}

  

  在處理配置bean時,ConfigurationClassParser#doProcessConfigurationClass()會首先迭代地處理所有巢狀的配置類,然後處理所有的@PropertySource註解來解析屬性源,再處理@ComponentScan註解實現自動掃描,再處理@Import註解來匯入配置類,注意,@SpringBootApplication註解由@EnableAutoConfiguration註解,而@EnableAutoConfiguration由@Import(EnableAutoConfigurationImportSelector.class)註解,同時它的@AutoConfigurationPackage由@Import(AutoConfigurationPackages.Registrar.class)註解,從這裡可以看到@EnableAutoConfiguration預設匯入了兩個類。

  對@ImportResource註解的處理

  處理@Bean註解的方法不會註冊bean,只在配置類中註冊相應的方法。

  處理超類

  processDeferredImportSelectors()的具體實現:

private void processDeferredImportSelectors() {
   List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
   this.deferredImportSelectors = null;
   Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);

   for (DeferredImportSelectorHolder deferredImport : deferredImports) {
       ConfigurationClass configClass = deferredImport.getConfigurationClass();
       try {
         // 獲取importSelector---在自動配置源資料中刪除不符合要求或者無法例項化的物件
         String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
         //處理import---迭代處理,最終呼叫processConfigurationClass處理自動配置的類
         processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
       } catch (BeanDefinitionStoreException ex) {
           throw ex;
       } catch (Throwable ex) {
           throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex);
       }
   }
}

  至此,Spring Boot的自動配置基本完成

3.4.5 registerBeanPostProcessors()

  根據實現了PropertyOrdered,Order介面,排序後註冊所有的BeanPostProcessor後置處理器,主要用於建立bean時,執行這些後置處理器的方法,這也是Spring 提供的擴充套件點,讓我們能夠插手Spring bean的建立過程。

 

3.4.6 重點 finishBeanFactoryInitialization() 實現SpringBean生命週期過程

  完成所所有單例bean的建立和例項化,其方法呼叫鏈如下

AbstractApplicationContext.finishBeanFactoryInitialization(方法最後一行)-----〉
AbstractBeanFactory.getBean---->AbstractBeanFactory.doGetBean------->
AbstractAutowireCapableBeanFactory.createBean------->
重點:AbstractAutowireCapableBeanFactory.doCreateBean(這個方法進行bean的生命週期)

  在例項化Bean的過程中,會按照順序執行,如下:

  resolveBeforeInstantiation會找到型別為InstantiationAwareBeanPostProcessor,且在Bean初始化前對Bean執行操作,例項化 ----》 AbstractAutowireCapableBeanFactory.doCreateBean() populateBean注入屬性initalizeBean方法呼叫擴充套件,順序如下: 

  1)如果Bean是BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,會執行者幾個的方法Aware的對應方法

  2)先執行所有BeanPostProcessor.postProcessBeforeInitialization()

  3) 反射呼叫init方法,如果Bean是InitializingBean,會先執行InitializingBean的afterPropertiesSet方法, 然後在執行自動以的init方法 、

  4)呼叫所有BeanPostProcessor.applyBeanPostProcessorsAfterInitialization()方法 @PostConstruct標記的方法,是在BeanPostProcessor.postProcessBeforeInitialization() 呼叫時執行,也就是有一個BeanPostProcessor用於處理標記了該註解的方法(InitDestroyAnnotationBeanPostProcessor),定時器等註解,原理也是一樣的,在解析BeanDefinition時,會將這些註解都解析成BeanDefinition的一個屬性

  bean生命週期執行過程圖如下

 

可以簡述為以下九步

  • 例項化bean物件(通過構造方法或者工廠方法)

  • 設定物件屬性(setter等)(依賴注入)

  • 如果Bean實現了BeanNameAware介面,工廠呼叫Bean的setBeanName()方法傳遞Bean的ID。(和下面的一條均屬於檢查Aware介面)

  • 如果Bean實現了BeanFactoryAware介面,工廠呼叫setBeanFactory()方法傳入工廠自身

  • 將Bean例項傳遞給Bean的前置處理器的postProcessBeforeInitialization(Object bean, String beanname)方法

  • 呼叫Bean的初始化方法; Spring檢測物件如果實現InitializingBean這個介面,就會執行他的afterPropertiesSet()方法,定製初始化邏輯。以及進行@PostConstruct註解邏輯實現

  • 將Bean例項傳遞給Bean的後置處理器的postProcessAfterInitialization(Object bean, String beanname)方法

  • 使用Bean

  • 容器關閉之前,呼叫Bean的銷燬方法

 

相關文章