SpringBoot框架——從SpringBoot看IoC容器初始化流程之方法分析


目錄

一、概觀Spring Boot

二、Spring Boot應用初始化

2.1 初始化入口

2.2 SpringApplication的run方法

2.3 方法分析

三、容器創建與初始化

3.1 creatApplicationContext()方法

3.2 prepareContext(context, environment, listener, applicationArguments, printedBanner)方法

3.3 refreshContext(context)方法

四、總結

一、概觀SpringBoot

隨着分布式、微服務和雲計算時代的到來,Spring Boot框架的重要性日益突顯。Spring官方給出的Spring Boot框架的特性:

  • 可以創建獨立的Spring應用
  • 直接內嵌Tomcat, Jetty 或者 Undertow,不再需要開發WAR類型文件
  • 提供各式的"starter"依賴,來簡化項目的創建配置
  • 任何時候都盡可能地自動化配置Spring和第三方庫
  • 提供猶如健康指標檢測和外部配置的生產環境特性
  • 完全沒有代碼生成和不需要xml配置

從官方給出的特性來看,Spring Boot適合做分布式系統和雲上應用的底層框架,內嵌容器不需要再安裝配置容器,而且提供了很多已經配置好的第三方框架和應用,並且主張“約定大於配置”,即拿來即用,適合使用java config注解配置,讓開發人員更關注與業務代碼。所以,在這么多誘惑下,自己便決定研究一下Spring Boot框架的源碼,從源碼來了解Spring Boot的迷人之處。

二、Spring Boot應用初始化

Spring框架的IoC和AOP是其強大之處,而Spring框架下的應用都會使用這兩種技術,所以使用該框架的開發人員都應該去了解ioc和aop技術。而Spring Boot是Spring框架的即用版,因此,從Spring Boot源碼中學習IoC容器的創建初始化以及AOP技術應用的思想,是我認為比較便捷的方法。同時,還可以學習到Spring Boot在整合Spring和第三方框架及應用的思想和技巧。接下來,我將從Spring Boot應用的啟動入口開始分析,逐步分析啟動流程。

2.1 初始化入口

下面是Spring Boot應用最簡單的啟動代碼:

@SpringBootApplication
public class MyApplication{
public static void main(String[] args){
SpringApplication.run(MyApplication.class, args );
}
}

從這段代碼可以知道,應用的主方法main調用了SpringApplication.run()方法,開啟了應用初始化。那么,接下來我們看看它是怎么初始化容器的。

2.2 SpringApplication的run方法

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);}
try {
listeners.running(context);
}catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

2.3 方法分析

  • StopWatch類:計時類,計算SpringBoot應用的啟動時間。
  • SpringBootExceptionReporter類:是一個回調接口,用於支持SpringApplication啟動錯誤的自定義報告。
  • configureHeadlessProper()方法:配置Headless模式配置,該模式下系統缺少顯示設備、鼠標或鍵盤,而服務器端往往需要在該模式下工作。
  • getRunListeners(args)方法:獲取SpringApplicationRunListeners類,是SpringApplicationRunListener類的集合。
  • SpringApplicationRunListener類:SpringApplication的run方法的監聽器。
  • DefaultApplicationArguments(args)類:提供訪問運行一個SpringApplication的arguments的訪問入口。
  • prepareEnvironment(listeners,applicationArguments)方法:創建和配置Environment,同時在調用AbstractEnvironment構造函數時生成PropertySourcesPropertyResolver類。
  • configureIgnoreBeanInfo(environment)方法:配置系統IgnoreBeanInfo屬性。
  • printBanner(environment)方法:打印啟動的圖形,返回Banner接口實現類。
  • createApplicationContext()方法:根據SpringApplication構造方法生成的webApplicationType變量創建一個ApplicationContext,默認生成AnnotationConfigApplicationContext。
  • getSpringFactoriesInstances(SpringBootExceptionRepoter.class, new Class[] {ConfigurableApplicationContext.class }, context)方法:獲取SpringBootExceptionReporter類的集合。
  • prepareContext(context, environment, listener, applicationArguments, printedBanner)方法:設置Environment,在ApplicationContext中應用所有相關的后處理,在刷新之前將所有的ApplicationContextInitializers應用於上下文,設置SpringApplicationRunLIstener接口實現類實現多路廣播Spring事件,添加引導特定的單例(SpringApplicationArguments, Banner),創建DefaultListableBeanFactory工廠類,從主類中定位資源並將資源中的bean加載進入ApplicationContext中,向ApplicationContext中添加ApplicationListener接口實現類。
  • refreshContext(context)方法:調用AbstractApplicationContext的refresh()方法初始化DefaultListableBeanFactory工廠類。
  • afterRefresh(CongigurableApplicationContext context, ApplicationArguments args)方法:在刷新ApplicationContext之后調用,在SpringAppliation中是方法體為空的函數,故不做任何操作。
  • listeners.started(context)方法:在ApplicationContext已經刷新及啟動后,但CommandLineRunners和ApplicationRunner還沒有啟動時,調用該方法向容器中發布SpringApplicationEvent類或者子類。
  • callRunners(context, applicationArguments)方法:調用應用中ApplicationRunner和CommanLineRunner的實現類,執行其run方法,調用時機是容器啟動完成之后,可以用@Order注解來配置Runner的執行順序,可以用來讀取配置文件或連接數據庫等操作。
  • listeners.running(context)方法:在容器刷新以及所有的Runner被調用之后,run方法完成執行之前調用該方法。調用之前得到的SpringApplicationRunListeners類running(context)方法。
  • 最后,向應用中返回一個之前獲得到的ApplicationContext。

三、容器創建與初始化

  在第二部分的SpringApplication的run()方法中,我們已經大致了解到了Spring Boot應用在啟動時做了哪些工作,與容器初始化相關的方法是createApplciationContext()、prepareContext(context, environment, listener, applicationArguments, printedBanner)以及refreshContext(context)。那這一部分將關注與Spring IoC容器的創建和初始化相關的SpringApplication方法。

3.1 creatApplicationContext()方法

  根據SpringApplication構造方法生成的webApplicationType變量創建一個ApplicationContext,默認生成AnnotationConfigApplicationContext。

(1)時序圖

SpringBoot框架——從SpringBoot看IoC容器初始化流程之方法分析

 

(2)方法的源碼

protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}catch (ClassNotFoundException ex) {
throw new IllegalStateException("Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

(3)方法分析

  a. 方法根據applicationContextClass變量是否為空,決定是否執行下面的switch語句,而applicationContextClass變量是由SpringApplicationBuilder類中的contextClass()方法調用ApplicationContext的setApplicationContextClass()賦值的,默認為空;

  b. webApplicationType變量是SpringApplication.run()方法調用構造方法時賦值的;

  c. switch語句通過反射根據webApplicationType生成對應的容器,分別是AnnotationConfigServletWebServerApplicationContext、AnnotationConfigReactiveWebServerApplicationContext以及AnnotationConfigApplicationContext的,默認生成的是AnnotationConfigApplicationContext,同時,其構造函數生成AnnotedBeanDefinitonReader和ClassPathBeanDefinitionScanner類;

  d. 最后,通過BeanUtils工具類將獲取到的容器類轉換成ConfigurableApplicationContext類,返回給應用使用。

3.2 prepareContext(context, environment, listener, applicationArguments, printedBanner)方法

  prepareContext方法的作用是,設置Environment,在ApplicationContext中應用相關的后處理,在刷新之前將任何的ApplicationContextInitializers應用於上下文,設置SpringApplicationRunLIstener接口實現類實現多路廣播Spring事件,添加引導特定的單例(SpringApplicationArguments, Banner),創建DefaultListableBeanFactory工廠類,從主類中定位資源並將資源中的bean加載進入ApplicationContext中,向ApplicationContext中添加ApplicationListener接口實現類。接下來,我們將從源碼入手,逐步分析prepareContext()方法所做的工作。

(1)prepareContext()源碼

private void prepareContext(ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}

(2)prepareContext時序圖

SpringBoot框架——從SpringBoot看IoC容器初始化流程之方法分析

 

(3)方法解析

  • context.setEnvironemnt(environment)方法:為容器設置環境,該Environment類是run()方法中的prepareEnvironment()方法獲取的,默認為StandardEnvironment類。
  • postProcessApplicationContext(context)方法:在ApplicationContext中應用相關的后處理。

    a. 根據應用中的beanNameGernerator引用是否為空(默認為空),決定是否向容器中注入BeanNameGenerator類的實現類;

    b. 根據resourceLoader引用是否為空(默認為DefaultResourceLoader類,在printBanner()階段獲得)以及context的類型,決定配置resource的地方和方式,若context(默認為AnnotationConfigApplicationContext)為GenericApplicationContext類或子類,則向context中添加    resourceLoader,若context為DefaultResourceLoader類或子類,則向context中添加resourceLoader類的ClassLoader類實例;

    c. 根據addConversionService的布爾值(默認為true),決定是否向容器中添加ApplicationConversionServivce類實例。

  • applyInitializers(context)方法:在容器刷新之前,應用所有的ApplicationContextInitializer接口實現類。遍歷執行getInitializers()方法得到的集合的initialize(context)方法初始化context容器,而for方法遍歷的ApplicationContextInitializer集合是應用執行SpringApplication構造函數時getSpringFactoriesInstances()方法設置的。
  • listeners.contextPrepared(context)方法:遍歷執行run方法里getRunListeners()得到的SpringApplicationRunListeners (SpringApplicationRunListener的集合)的contextPrepared(context)方法。執行時機是,ApplicationContext容器完成創建和准備之后,並且只調用一次。容器提供的SpringApplicationRunListener接口實現類是EventPublishingRunListener類,該類構造函數生成的SimpleApplciationEventMulticaster類用來多路廣播發布SpringApplicationEvent接口的實現類。
  • logStartupInfo(context.getParent()==null)方法:記錄啟動信息,其子類可以覆蓋該方法以添加附加信息。
  • logStartupProfileInfo(context)方法:記錄活動配置文件信息。
  • context.getBeanFactory()方法:調用之前得到的ApplicationContext容器(默認AnnotationConfigApplicationContext)的getBeanFactory()得到一個BeanFactory接口實現類(默認DefaultListableBeanFactory類),轉換為ConfigurableListableBeanFactory類。
  • beanFactory.registerSingleton("springApplicationArguments", applicationArguments)方法:往容器中注冊ApplicationArguments接口實現類(默認DefaultApplicationArguments類)的單例。
  • beanFactory.registerSingleton("springBootBanner", printedBanner)方法:向容器中添加printBanner(environment)方法返回的Banner類的單例。
  • ((DefaultListableBeanFactory) beanfactory).setAllowBeanDefinitionOverring(this.allowBeanDefinitionOverriding)方法:設置BeanDefinitio覆蓋的開關。
  • getAllSources()方法:獲取到應用中所有的資源,即Bean的資源定位階段。該資源獲取的地點是,在SpringApplication構造方法中產生,將run(MyApplication.class,args)中的MyApplication.class轉換存儲到LinkedHashSet<>中,並返回一個該資源Set的引用primarySources,在getAllSource()方法中獲取該primarySources。
  • Assert.notEmpty(sources, "Sources must not be empty")方法:斷言,判斷獲取到的sources是否為空,為空則停止應用並返回錯誤信息。
  • load(context, sources.toArray(new Object[0]))方法:從上面獲取的資源中加載bean進入ApplicationContext中,即bean的加載階段。加載流程如下:

             a.創建了BeanDefinitionLoader類,將傳入的context容器類型轉換為BeanDefinitionRegistry(該轉換局部生效);

    b.創建了AnnotedBeanDefinitionReader類、AnnotationScopeMetadataResolver類、AnnotationBeanNameGenerator類以及ConditionEvaluator類;

    c.創建XmlBeanDefinitionReader類、SimpleSaxErrorHandler類、XmlValidationModeDetector類以及NameThreadLocal類;

    d. 創建了ClassPathBeanDefintionScannerl類以及GroovyBeanDefintionReader類(該類根據BeanDefinitionLoader中的isGroovyPresent()返回的布爾值決定是否創建);

    e. 配置得到的BeanDefinitionLoader,並調用其load()方法,開始加載BeanDefinition;

    f. 根據傳入的資源的類型,決定加載Bean的方式以及BeanDefinition的類型(默認為AnnotatedGenericBeanDefinition類);

    g. 解析含有@Scope注解的BeanDefinition獲得其ScopeMetadata,並將scope添加到獲得的BeanDefinition中; h. 解析BeanDefinition獲得beanName;

    i. 解析含有@Lazy注解的BeanDefinition,根據注解屬性值決定是否執行setLazyInit()方法;

    j. 遍歷函數輸入參數BeanDefinitionCustomizer(該接口是功能性接口)的集合,執行其customizer(abd)方法;

    k. 將剛才得到的BeanDefinition和beanName添加到BeanDefinitionHolder中;

    l. 利用AOP框架創建作用域代理類,根據剛剛獲得的ScopeMetadata的getScopedProxyMode()方法返回的值,ScopedProxyMode 決定是否生成代理類並決定使用jdk代理生成代理類還是cglib生成代理類,並將得到的proxyDefinition代替之前的BeanDefinition添加到BeanDefinitionHolder中;

    m. 向容器中注冊別名aliases和beanName;

  • listeners.contextLoaded(context)方法:遍歷執行之前獲得的SpringApplicationRunListener接口實現類的contextLoaded(context)方法。

3.3 refreshContext(context)方法

  調用AbstractApplicationContext的refresh()方法初始化DefaultListableBeanFactory工廠類。

(1)refreshContext(context)源碼

private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
}
}
}

  調用的AbstractApplicationContext.refresh()源碼:

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}

(2)refreshContext(context)時序圖

  下面時refreshContext(context)實際刷新容器的AbstractApplicationContext.refresh()的時序圖:

SpringBoot框架——從SpringBoot看IoC容器初始化流程之方法分析

 

(3)方法分析

  • prepareRefresh()方法:為刷新准備好容器。

             a. 設置啟動時間;

             b. 設置標示當前context是否活動的標簽,active為true,closed為false,類型為AtomicBoolean;

             c. 在context環境中初始化placeholder屬性源,默認不做任何事情;

             d. 驗證所有標記required的property都是可解析的;

             e. 創建ApplicationEvent的集合,即LinkedHashSet<ApplicationEvent>。一旦多路廣播器可用(即prepareContext()階段得到的SimpleApplicationEventMulticaster類),便允許發布早期的ApplicationEnvent的集合;

  • obtainFreshBeanFactory()方法:告訴子類刷新內部的bean工廠類。

             a. 持有一個工廠類單例(默認為DefaultListableBeanFactory),並依靠調用者通過工廠類單例或構造方法注冊bean;

             b. 將在AbstarctApplicationContext類生成的id和在DefaultListableBeanFatory生成指向自身的弱引用,存儲進入一個由DefaultListableBeanFactory持有的Map中。

  • prepareBeanFactory(beanFactory)方法:准備在context中要使用的beanFactory。配置工廠的標准context特性,比如容器的ClassLoader和后處理器。

             a. 設置ClassLoader;

             b. 設置BeanExpressionResolver接口實現類(為StandardBeanExpressionResolver類);

             c. 設置PropertyEditorRegistrar接口實現類(為ResourceEditorRegistrar類);

             e. 將ApplicationContextAwareProcessort添加進入應用獲得的工廠類實例持有的CopyOnWriteArrayList的一個引用中;

             f. 將EnvironmentAware.class、EmbeddedValueResolverAware.class、ResourceLoaderAware.class、ApplicationEventPublisherAware.class、MessageSourceAware.class、MessageSourceAware.class 添加進入應用獲得的工廠類實例持有的HashSet的一個引用中;

             g. 在普通工廠類中未注冊成為可解析類型的工廠類接口,而MessageSource作為bean被注冊(查找到並自動裝配)。

             h. 將BeanFactory.class、ResourceLoader.class、ApplicationEventPublisher.class、ApplicationContext.class 添加進入應用獲得的工廠類實例持有的ConcurrentHashMap<Class<?>, Object>的一引用中;

             i. 注冊為了檢測內部bean的早期后處理器,例如ApplicationListeners;

             j. 將ApplicationListenerDetector的實例、LoadTimeWeaverAwareProcessor的實例添加進入應用獲得的工廠類實例持有的CopyOnWriteArrayList<BeanPostProcessor>的一個引用中;

             k. 為持有的工廠類設置臨時可以匹配類型的ClassLoader,為ContextTypeMatchClassLoader類;

             l. 配置默認的環境單例bean;

  • postProcessBeanFactory(beanFactory)方法:允許容器子類中的bean工廠執行后處理。該方法執行時機時,在ApplicationContext內部bean工廠類標准初始化之后修改它,這時所有的BeanDifinition已經被加載,但是還沒有被實例化。繼承這個方法允許某些AbstractApplicationContext類的子類中注冊特殊的類似BeanPostProcessors的類。默認不做任何操作。
  • invokeBeanFactoryPostProcessors(beanFactory)方法:實例化所有已經注冊的BeanFactoryPostProcessor的bean(實例化為單例),並遵循已給出的明確order值調用它,bean實例化與依賴注入開始階段。

    a. 實際調用了PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessor(beanfactory, getBeanFactoryPostProcessor)方法,在這個方法里完成了實例化和調用任務;

              c. 不實例化FactoryBean,並保留所有常規bean,不初始化它們,讓之后的bean工廠后處理器應用他們;

             d. 區分開實現了PriorityOrdered類的BeanDefinitionRegistryPostProcessor類,將其實例化並裝入一個ArrayList的容器中;

             e. 將剛剛獲得的BeanDefinitionRegistryPostProcessor的集合根據order的值排序;

             f. 遍歷調用得到的BeanDefinitionRegistryPostProcessor類bean的postProcessBeanDefinitionBeanDefinitionRegistry(registry)方法;

             g. 清除BeanDefinitionRegistryPostProcessor的ArrayList集合里的bean;

             h. 區分開實現了Ordered類的BeanDefinitionRegistryPostProcessor類,將其實例化並裝入一個ArrayList的容器中,並重復執行一次e到g的步驟;

             i. 最后,調用所有其他的BeanDefinitionRegistryPostProcessor,直到不再出現其他的BeanDefinitionRegistryPostProcessor,也重復執行一次e到g的步驟;

             j. 調用到目前為止的已處理的所有處理器的postProcessBeanFactory回調;

             g. 調用context實例注冊的factory的processor;

             i. 清空緩存的合並的Bean定義,因為后處理器可能會修改原始的元數據,例如,替換值中的占位符。

  • registerBeanPostProcessors(beanFactory)方法:注冊攔截bean創建的bean處理器。

             a. 向context持有的bean factory注冊BeanPostProcessorChecker,該檢查器其用來記錄在BeanPostProcessor實例化期間創建bean時的info信息,即當所有BeanPostProcessor都不對bean進行后處理操作時記錄。

             b. 將所有的BeanPostProcessor按照實現PriorityOrdered、Oedered和剩下的區別,分別添加進三個ArrayList容器;

             c. 對剛剛獲得ArrayList分別根據order值進行排序,最后整合后注冊進入bean factory中;

             d. 重新注冊后處理器,用於檢測像ApplicationListener的內部類,將其移動到后處理器鏈的末端,用於提取代理等作用;

  • initMessageSource()方法:為context初始化message源。從容器中獲得MessageSource的bean,若沒有定義,則會調用父類的MessageSource(無值,並會打印出沒有message source的日志信息)。此例為單例。
  • initApplicationEventMulticaster()方法:實例化應用事件多路廣播器ApplicationEventMulticaster。從容器中獲取ApplicationEventMulticaster的bean,若沒有注冊,則注入SimpleApplicationEventMulticaster類的bean。
  • onRefresh()方法:該方法使模板方法,在特定的context子類中初始化其他特殊的bean。

             a. 在GenericWebApplicationContext、StaticWebApplicationContext中,該方法初始化了context的ThemeSource;

             b. 在ServletWebServerApplicationContext、ReactiveWebServerApplicationContext中,該方法初始化類context的TnemeSource並創建了一個ServerManager。

  • registerListeners()方法: 檢測監聽器並注冊它們。向剛才獲得的ApplicationEventMulticaster中注冊實現了ApplicationListener的監聽器bean,但不影響那一些可以不用生成bean就可以加載的監聽器。
  • finishBeanFactoryInitialization(beanFactory)方法:實例化所有剩下的單例bean(沒有執行lazy初始化)。

             a. 初始化context的類型轉換服務;

             b. 如果之前沒有任何注冊的bean后處理器(比如,一個PropertyPlaceholderConfigurer的bean),則注冊一個默認的內嵌的值解析器,在這一觀點下,優先解析注解屬性值;

             c. 盡早初始化LoadTimeWeaverAwarebean,以便盡早注冊它們的轉換器;

             d. 停止使用臨時的類型匹配類加載器;

             e. 允許緩存所有的bean定義元數據,不需要進一步修改了;

             f. 實例化所有剩下的單例(沒有Lazy初始化的bean);

  • finishRefresh()方法:發布相應的事件。

             a. 清除context級別的資源緩存(例如,掃描得來的ASM元數據);

             b. 為context初始化生命周期處理器;

             c. 首先向生命周期處理器傳播刷新;

             d. 發布最后的事件(ContextRreshedEvent);

             e. 若激活的話,便參與LiveBeansView類的mbean,。

  • destroyBeans()方法:摧毀已經創建的bean,避免懸空資源。
  • cancelRefresh(ex)方法:取消刷新,設置active變量為false。
  • resetCommonCaches()方法:重置Spring中的內省緩存,因為應用可能不再需要單例bean的元數據了。

             a. 清除聲明方法緩存,清除聲明變量緩存(ConcurrentReferenceHashMap數據類型);

             b. 清除注解相關緩存;

             c. 清除可解析類型相關緩存;

             d. 清除相關類加載器緩存(ConcurrentHashMap)。

四、總結

  到此為止,分析了Spring Boot應用啟動過程run方法中,自己比較感興趣的三個方法,再以此延伸又接觸到了更多的相關類和相關方法,重新復習了許多java知識(繼承、重載、重寫、接口、反射以及設計模式)。雖然自己還沒有能力寫出這么優美的框架,但是從分析源碼中自己學習到了不少的框架設計知識,接觸到比較底層的設計思想。不盡人意的是,有些方法和重要類的分析由於自己能力有限,解釋得還有些模糊,決定在接下來的文章里將這些遺憾彌補回來。歡迎指正!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM