SpringBoot啓動流程源碼分析--SpringBoot源碼分析(一)

 

1,概述

SpringApplication類用來啓動Spring應用,默認會執行以下主要步驟來啓動應用:

1),根據classpath創建一個相應的ApplicationContext
2),註冊一個CommandLinePropertySource來曝光命令行參數作爲spring屬性
3),刷新application context來加載所有的單例bean
4),觸發CommandLineRunner的bean實例的run方法

上面翻譯自SpringApplication的官方註釋。

2,SpringBoot的啓動流程分析

2.0 啓動SpringBoot

@SpringBootApplication
public class MvcApplication {

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

}

2.1 SpringApplication構造函數

因爲SpringApplication.run(MvcApplication.class, args);方法時首先會new 一個SpringApplication對象,然後再執行其相應的run方法,所以先來看下SpringApplication的構造函數: 


public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		// primarySources就是SpringApplication.run(MvcApplication.class, args);中的MvcApplication.class
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 根據不同的類路徑來確定WebApplicationType
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		/**
		 * 初始化 initializers 屬性:
		 * 從spring.factories配置文件中獲得ApplicationContextInitializer接口的以下實現類並初始化到 initializers 屬性中
		 * # Application Context Initializers
		 * org.springframework.context.ApplicationContextInitializer=\
		 * org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
		 * org.springframework.boot.context.ContextIdApplicationContextInitializer,\
		 * ......
		 */
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		/**
		 * 初始化 listeners 屬性:
		 * 從spring.factories配置文件中獲得ApplicationListener接口的以下實現類並初始化到 listeners 屬性中
		 * # Application Listeners
		 * org.springframework.context.ApplicationListener=\
		 * org.springframework.boot.ClearCachesApplicationListener,\
		 * ......
		 */
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 推斷應用類型
		this.mainApplicationClass = deduceMainApplicationClass();
	}

該構造函數主要是爲一些變量屬性賦值:

  • primarySources屬性,即SpringApplication.run(MvcApplication.class, args);中傳入的MvcApplication.class,該類爲SpringBoot項目的啓動類,主要從該類的configuration類加載bean 
  • webApplicationType屬性,代表應用類型,根據classpath存在的相應Application類來判斷,詳情請見2.1.1 deduceFromClasspath()方
  • initializers屬性,ApplicationContextInitializer 數組,從spring.factories配置文件中加載,見2.1.2 getSpringFactoriesInstances(Class<T> type)方法。
  • listeners屬性,ApplicationListener 數組,從spring.factories配置文件中加載
  • mainApplicationClass屬性,獲得哪個類調用了main(String[] args)方法,比如mainApplicationClass這裏是“class com.jinyue.springboot.mvc.MvcApplication”啓動了main方法,僅僅用來打印下日誌

2.1.1 deduceFromClasspath()


static WebApplicationType deduceFromClasspath() {
   // 若classpath中不存在"org.springframework." + "web.servlet.DispatcherServlet"和"org.glassfish.jersey.servlet.ServletContainer"
   // 則返回WebApplicationType.REACTIVE,表明是reactive應用
   if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
         && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      return WebApplicationType.REACTIVE;
   }
   // 若{ "javax.servlet.Servlet",
   //       "org.springframework.web.context.ConfigurableWebApplicationContext" }
   // 都不存在在classpath,則說明是不是web應用
   for (String className : SERVLET_INDICATOR_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
         return WebApplicationType.NONE;
      }
   }
   // 最終返回普通的web應用
   return WebApplicationType.SERVLET;
}

根據classpath判斷應用類型,通過反射加載classpath判斷指定的標誌類存在與否來分別判斷是reactive應用,web應用還是非web應用。

2.1.2 getSpringFactoriesInstances(Class<T> type)

// 返回spring.factories中獲取類名並創建的對象
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		// 加載指定類型對應的,在 `META-INF/spring.factories` 裏的類名的數組
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		// 根據 `META-INF/spring.factories` 裏獲取的類型創建相應的對象
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		// 排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

先根據接口類從項目的所有spring.factories配置文件中獲得相應的具體實現類放入names集合,然後再調用createSpringFactoriesInstances方法創建具體的實例,下面是createSpringFactoriesInstances方法:

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		// 先創建ArrayList集合,大小即爲names的大小
		List<T> instances = new ArrayList<>(names.size());
		// 遍歷
		for (String name : names) {
			try {
				// 根據name通過反射獲得相應的類
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				// 獲得構造器
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				// new 出一個對象來
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				// 將對象添加instances集合中
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

根據傳入的接口類型從spring.factories配置文件中加載相應的實例,比如:getSpringFactoriesInstances(ApplicationContextInitializer.class)方法根據ApplicationContextInitializer.class接口類去spring.factories配置文件尋找具體實現類,最終初始化到初始化 initializers 屬性中,經過調試,ApplicationContextInitializer接口具體實現類有:

而ApplicationListener的具體實現類如下:

2.2 SpringApplication的run(String… args)啓動函數分析

前面分析了SpringApplication的構造函數,下面來分析該類的run方法。

public static void main(String[] args) throws Exception {
   SpringApplication.run(new Class<?>[0], args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   // 新建SpringApplication對象,再調用run方法
   return new SpringApplication(primarySources).run(args);
}
public ConfigurableApplicationContext run(String... args) {
   // stopWatch用於統計run啓動過程時長
   StopWatch stopWatch = new StopWatch();
   // 開始計時
   stopWatch.start();
   // 創建ConfigurableApplicationContext對象
   ConfigurableApplicationContext context = null;
   // exceptionReporters集合用來存儲SpringApplication啓動過程的異常,SpringBootExceptionReporter且通過spring.factories方式來加載
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   // 配置headless屬性
   configureHeadlessProperty();
   /**
    * 從spring.factories配置文件中加載到EventPublishingRunListener對象並賦值給SpringApplicationRunListeners
    * # Run Listeners
    * org.springframework.boot.SpringApplicationRunListener=\
    * org.springframework.boot.context.event.EventPublishingRunListener
    */
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // 啓動SpringApplicationRunListeners監聽
   listeners.starting();
   try {
      // 創建ApplicationArguments對象,封裝了args參數
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      // 備配置參數有app.properties,外部配置參數比如jvm啓動參數等
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      // 配置spring.beaninfo.ignore屬性
      configureIgnoreBeanInfo(environment);
      // 打印springboot的bannner
      Banner printedBanner = printBanner(environment);
      // 根據不同類型創建不同類型的spring applicationcontext容器
      context = createApplicationContext();
      /**
       * 異常報告
       * 從spring.factories配置文件中加載exceptionReporters,其中ConfigurableApplicationContext.class作爲FailureAnalyzers構造方法的參數
       * # Error Reporters
       * org.springframework.boot.SpringBootExceptionReporter=\
       * org.springframework.boot.diagnostics.FailureAnalyzers
       */
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      // 準備容器事項:調用各個ApplicationContextInitializer的initialize方法
      // 和觸發SpringApplicationRunListeners的contextPrepared及contextLoaded方法等
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      // 刷新容器,這一步至關重要
      refreshContext(context);
      // 執行刷新容器後的後置處理邏輯,注意這裏爲空方法
      afterRefresh(context, applicationArguments);
      // 停止stopWatch計時
      stopWatch.stop();
      // 打印springboot的啓動時常
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      // 觸發SpringApplicationRunListener的started方法,通知spring容器已經啓動
      listeners.started(context);
      // 調用ApplicationRunner和CommandLineRunner的run方法,實現spring容器啓動後需要做的一些東西
      callRunners(context, applicationArguments);
   }
   // 若上面的方法拋出異常,將異常添加到exceptionReporters集合中,並拋出 IllegalStateException 異常。
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      // 當容器刷新完畢等,觸發SpringApplicationRunListeners數組的running方法
      listeners.running(context);
   }
   catch (Throwable ex) {
      // 若上面的方法拋出異常,將異常添加到exceptionReporters集合中,並拋出 IllegalStateException 異常。
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

上面的run方法比較長,下面捋一下,現在將run方法關鍵做的事情總結如下:

1,利用stopWatch用於統計run啓動過程時長

2,調用configureHeadlessProperty()方法配置headless即“java.awt.headless”屬性,默認爲ture,那麼:做了這樣的操作後,SpringBoot想幹什麼呢?

其實是想設置該應用程序,即使沒有檢測到顯示器,也允許其啓動.對於服務器來說,是不需要顯示器的,所以要這樣設置.

參考:https://www.cnblogs.com/wangxuejian/p/10603034.html

3,獲取SpringApplicationRunListeners,並啓動SpringApplicationRunListener的監聽,此時利用EventPublishingRunListener

的initialMulticaster對象來發布ApplicationStartingEvent事件,表示SpringApplication開始啓動,監聽ApplicationStartingEvent事件的listeners們將會執行相應邏輯。

    注意:1)EventPublishingRunListener擁有SpringApplication屬性。

4,調用prepareEnvironment方法準備environment,比如準備配置參數有servlet配置參數,外部配置參數比如jvm啓動參數等。詳情請見2.2.1 prepareEnvironment方法。

5,調用printBanner(environment)方法打印springboot的bannner

6,調用createApplicationContext()方法根據webApplicationType創建容器context,因爲是web項目,這裏創建的是AnnotationConfigServletWebServerApplicationContext容器對象,詳情請見2.2.2 createApplicationContext方法

7,調用getSpringFactoriesInstances方法創建exceptionReporters集合,該集合用於收集springboot啓動時的異常。

  •      該exceptionReporters集合只有一個FailureAnalyzers對象,但是FailureAnalyzers又有17個FailureAnalyzer個具體實現類,如下圖:

8,調用prepareContext方法準備容器事項,比如調用調用各個ApplicationContextInitializer的initialize初始化方法
      和觸發SpringApplicationRunListeners的contextPrepared及contextLoaded方法等,詳情請見2.2.3 prepareContext方法

9,調用refreshContext方法最終調用AbstractApplicatioinContetext.refresh()方法刷新容器,這一步至關重要,因爲很多spring重要的邏輯都在這裏處理,請見2.2.4 refreshContext方法

10,調用afterRefresh方法執行刷新容器後的後置處理邏輯,注意目前這裏爲空方法,留給子類去實現。

11,觸發SpringApplicationRunListener的started方法,發佈ApplicationStartedEvent事件,通知spring容器已經啓動,相應listener監聽該事件執行相應處理邏輯。

12,調用callRunners方法,即會調用ApplicationRunner和CommandLineRunner的run方法,實現spring容器啓動後需要做的一些東西,詳情請見2.2.5 callRunners方法

 

2.2.1 prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		/**
		 * 根據webApplicationType創建不同類型的ConfigurableEnvironment對象:
		 * 		case SERVLET:
		 * 			return new StandardServletEnvironment();
		 * 		case REACTIVE:
		 * 			return new StandardReactiveWebEnvironment();
		 * 		default:
		 * 			return new StandardEnvironment();
		 *
		 * 比如servlet的初始化標籤<servletContextInitParams />
		 */
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		// 對創建的environment進行配置
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		// 將environment最終封裝到PropertySource對象中
		ConfigurationPropertySources.attach(environment);
		// 通知 SpringApplicationRunListener 的數組,環境變量已經準備完成
		listeners.environmentPrepared(environment);
		// 爲SpringApplication綁定環境變量environment
		bindToSpringApplication(environment);
		// 如果不是自定義的化境變量,若有必要則進行轉換
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		// 如果有 attach 到 environment 上的 MutablePropertySources ,則添加到 environment 的 PropertySource 中。
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

上面代碼首先根據webApplicationType創建不同的environment對象,這裏創建的是StandardServletEnvironment對象;然後對environment對象進行配置,比如增加 environment 的 PropertySource 屬性源,還有配置哪個profile爲actived;environment環境變量準備好後,此時發佈ApplicationEnvironmentPreparedEvent事件,執行environment準備好後的相關邏輯;然後再將environment綁定到SpringApplication,對非自定義的envoronment進行轉換等。

2.2.2 createApplicationContext

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);
	}

2.2.3 prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		// 設置context的environment屬性
		context.setEnvironment(environment);
		// 根據情況對ApplicationContext應用一些相關的後置處理,比如設置resourceLoader屬性等
		postProcessApplicationContext(context);
		// 在容器刷新前調用ApplicationContextInitializer的初始化方法
		applyInitializers(context);
		// 在sources加載前,一旦context容器被創建且已準備好,會觸發該事件方法通知容器已經準備好
		listeners.contextPrepared(context);
		// 打印啓動相關日誌
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			/**
			 * 此處打印的日誌如下:
			 * ....MVCApplication  : The following profiles are active: prod
			 */
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		// 得到beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		// 向容器中註冊相關單例bean
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// Load the sources
		// 加載BeanDefinition等,這裏應該是JavaConfig上的一些定義的bean
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// 加載bean到application context.
		load(context, sources.toArray(new Object[0]));
		// 在context容器刷新前,一旦容器被加載就會觸發調用該方法,通知spring容器已經加載完成
		listeners.contextLoaded(context);
	}

prepareContext主要是準備context,主要做了以下事情:

  • postProcessApplicationContext(context),子類可以覆蓋該方法做一些定製處理
  • applyInitializers(context):這個是將之前從spring.factories中加載的ApplicationContextInitializer接口的具體實現類逐個應用其initialize初始化方法,執行一些初始化邏輯

  • listeners.contextPrepared(context):發佈ApplicationContextInitializedEvent事件,說明context已經準備好

  • getAllSources():將primarySource加載出來,應該是之後要對其配置的javaconfig或xml配置的bean進行加載,這裏留個疑問先。
  • load(context, sources.toArray(new Object[0])):加載所有的配置文件比如javaconfig和xml配置文件的bean定義,這裏創建了一個BeanDefinitionLoader對象;BeanDefinitionLoader作爲AnnotatedBeanDefinitionReader,XmlBeanDefinitionReader和ClassPathBeanDefinitionScanner的門面,從底層源加載bean定義
  • listeners.contextLoaded(context):發佈ApplicationPreparedEvent,說明context已經加載完畢。

2.2.4 refreshContext

    /**
	 * 刷新容器
	 * @param context
	 */
	private void refreshContext(ConfigurableApplicationContext context) {
		// 刷新容器
		refresh(context);
		// 若註冊了shutdownHook鉤子,則註冊shutdownHook鉤子
		// JVM shutdownHook的作用是當jvm關閉時,關閉context容器,銷燬相關bean
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}


    protected void refresh(ApplicationContext applicationContext) {
		// 斷言:applicationContext必須是AbstractApplicationContext的子類,否則報錯
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		// 刷新容器
		((AbstractApplicationContext) applicationContext).refresh();
	}



	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// 在context刷新前做一些準備工作,比如設置context的啓動日期,active flag和property sources的初始化工作
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 讓子類刷新其內部bean factory,實質就是再新建一個DefaultListableBeanFactory類型的bean factory對象
			// 加載xml配置的bean定義,注意加載annotation的bean定義應該是在invokeBeanFactoryPostProcessors方法中加載??
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 上面那一步工廠剛建好,什麼都沒有,因此需要準備一些配置,
			// 比如配置factory的標準容器特性,比如容器的類加載器和一些後置處理器比如ApplicationContextAwareProcessor 等
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 在經過上面的標準初始化後,修改應用容器的內部bean factory。
				// 在這一步,所有的bean definitions將會被加載,但此時bean還不會被實例化
				// 此時會註冊一些BeanPostProcessors
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// Bean工廠的後置處理器的相關邏輯,BeanFactoryPostProcessor(觸發時機:bean定義註冊之後bean實例化之前)
				// 和BeanDefinitionRegistryPostProcessor(觸發時機:bean定義註冊之前),所以可以在Bean工廠的後置處理器中修改Bean的定義信息,
				// 比如是否延遲加載、加入一些新的Bean的定義信息等實例化所有註冊的BeanFactoryPostProcessor beans,並且調用其後置處理方法
				// BeanFactoryPostProcessor 是針對 BeanFactory 的擴展,主要用在 bean 實例化之前,讀取 bean 的定義,並可以修改它。
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 實例化並註冊所有Bean的後置處理器:BeanPostProcessor beans,冊所有的 BeanPostProcessor,將所有實現了 BeanPostProcessor 接口的類加載到 BeanFactory 中。
				// registerBeanPostProcessors 方法主要用於處理 BeanPostProcessor 接口,調用時機:必須在所有bean的實例化之前調用
				// BeanPostProcessor 是針對 bean 的擴展,主要用在 bean 實例化之後,執行初始化方法前後,允許開發者對 bean 實例進行修改。
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 這裏的邏輯主要跟國際化有關
				initMessageSource();

				// Initialize event multicaster for this context.
				// 初始化事件廣播器,如果自定義了廣播器,就用自定義的,
				// 如果沒有自定義就用默認得SimpleApplicationEventMulticaster廣播器。並且把廣播器設置到上下文的applicationEventMulticaster屬性中。
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 這個是個模板方法,留給子類實現,在特殊的bean初始化之前和單例bean實例化之前調用
				// 這裏應該可以擴展ThemeSource接口
				onRefresh();

				// Check for listener beans and register them.
				// 註冊實現了ApplicationListener接口的監聽器,這裏不會影響其他監聽器的使用
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 完成容器bean factory的初始化,並初始化所有剩餘的單例bean
				// 這個方法在容器刷新過程中非常重要,因爲所有的bean,如果不是lazy-init的都會在這一步進行實例化,並且做一些處理。
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 完成容器的刷新共工作,並且調用生命週期處理器的onRefresh()方法,並且發佈ContextRefreshedEvent事件
				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();
			}
		}
	}

refresh方法是spring容器的重頭戲,很多重要複雜的邏輯都在這裏實現。

比如所有beanFactory的創建,所有bean定義的加載,實例化,註冊一些事件監聽器比如實現了ApplicationListener接口的監聽器,還有一些後置處理方法也在這裏處理,下面主要講下後置處理方法,beanFactoryPostProcessor和beanPostProcessor等後置處理器也在這裏實現調用相應的後置處理方法,比如beanFactoryPostProcessor是bean工廠的bean屬性處理容器,說通俗一些就是可以管理我們的bean工廠內所有的beandefinition(未實例化)數據,可以隨心所欲的修改屬性;BeanPostProcessor是Spring IOC容器給我們提供的一個擴展接口,通過該接口的postProcessBeforeInitialization和postProcessAfterInitialization方法可以在bean的初始化前後執行一些自定義的邏輯。

2.2.5 callRunners

private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

3,總結

目前springboot的啓動流程分析就已經結束了,第一次寫源碼解析的博文,參考了很多文章,且寫的巨慢。。。

由於作者水平有限,若寫的有錯誤的地方還請評論糾正, 不勝感激,謝謝。

參考:

1,https://www.cnblogs.com/youzhibing/p/9622441.html

2,https://blog.csdn.net/yhahaha_/article/details/88890527

3,https://blog.csdn.net/lz710117239/article/details/80141048

4,https://www.cnblogs.com/youzhibing/p/9697825.html

5,https://www.jianshu.com/p/fca013ec1764

6,https://www.cnblogs.com/toby-xu/p/11332666.html

7,https://blog.csdn.net/v123411739/article/details/87886900

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章