日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

SpringBoot2.x启动原理概述

發(fā)布時(shí)間:2024/4/13 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot2.x启动原理概述 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Spring Boot 的入口類(lèi)

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

做過(guò) Spring Boot 項(xiàng)目的都知道,上面是 Spring Boot 最簡(jiǎn)單通用的入口類(lèi)。入口類(lèi)的要求是最頂層包下面第一個(gè)含有 main 方法的類(lèi),使用注解 @SpringBootApplication 來(lái)啟用 Spring Boot 特性,使用 SpringApplication.run 方法來(lái)啟動(dòng) Spring Boot 項(xiàng)目。

來(lái)看一下這個(gè)類(lèi)的run方法調(diào)用關(guān)系源碼:

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

第一個(gè)參數(shù)primarySource:加載的主要資源類(lèi)

第二個(gè)參數(shù) args:傳遞給應(yīng)用的應(yīng)用參數(shù)

先用主要資源類(lèi)來(lái)實(shí)例化一個(gè) SpringApplication 對(duì)象,再調(diào)用這個(gè)對(duì)象的 run 方法,所以我們分兩步來(lái)分析這個(gè)啟動(dòng)源碼。


SpringApplication 的實(shí)例化過(guò)程

接著上面的?SpringApplication?構(gòu)造方法進(jìn)入以下源碼:

public SpringApplication(Class<?>... primarySources) {this(null, primarySources); }public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {// 1、資源初始化資源加載器為 nullthis.resourceLoader = resourceLoader;// 2、斷言主要加載資源類(lèi)不能為 null,否則報(bào)錯(cuò)Assert.notNull(primarySources, "PrimarySources must not be null");// 3、初始化主要加載資源類(lèi)集合并去重this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 4、推斷當(dāng)前 WEB 應(yīng)用類(lèi)型this.webApplicationType = deduceWebApplicationType();// 5、設(shè)置應(yīng)用上線文初始化器setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 6、設(shè)置監(jiān)聽(tīng)器setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 7、推斷主入口應(yīng)用類(lèi)this.mainApplicationClass = deduceMainApplicationClass();}

可知這個(gè)構(gòu)造器類(lèi)的初始化包括以下 7 個(gè)過(guò)程。
1. 資源初始化資源加載器為 null

this.resourceLoader = resourceLoader;

2. 斷言主要加載資源類(lèi)不能為 null,否則報(bào)錯(cuò)

Assert.notNull(primarySources, "PrimarySources must not be null");

3. 初始化主要加載資源類(lèi)集合并去重

this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

4. 推斷當(dāng)前 WEB 應(yīng)用類(lèi)型

this.webApplicationType = deduceWebApplicationType();

來(lái)看下?deduceWebApplicationType?方法和相關(guān)的源碼:

private WebApplicationType deduceWebApplicationType() {if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {return WebApplicationType.REACTIVE;}for (String className : WEB_ENVIRONMENT_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}return WebApplicationType.SERVLET; }private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."+ "web.reactive.DispatcherHandler";private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."+ "web.servlet.DispatcherServlet";private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"}; public enum WebApplicationType {/*** 非 WEB 項(xiàng)目*/NONE,/*** SERVLET WEB 項(xiàng)目*/SERVLET,/*** 響應(yīng)式 WEB 項(xiàng)目*/REACTIVE}

這個(gè)就是根據(jù)類(lèi)路徑下是否有對(duì)應(yīng)項(xiàng)目類(lèi)型的類(lèi)推斷出不同的應(yīng)用類(lèi)型。

5. 設(shè)置應(yīng)用上線文初始化器

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

ApplicationContextInitializer?的作用是什么?源碼如下。

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {/*** Initialize the given application context.* @param applicationContext the application to configure*/void initialize(C applicationContext);} }

用來(lái)初始化指定的 Spring 應(yīng)用上下文,如注冊(cè)屬性資源、激活 Profiles 等。

來(lái)看下 setInitializers 方法源碼,其實(shí)就是初始化一個(gè) ApplicationContextInitializer 應(yīng)用上下文初始化器實(shí)例的集合。


?

public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {this.initializers = new ArrayList<>();this.initializers.addAll(initializers); }

再來(lái)看下這個(gè)初始化 getSpringFactoriesInstances 方法和相關(guān)的源碼:

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 = Thread.currentThread().getContextClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances; }

設(shè)置應(yīng)用上下文初始化器可分為以下 5 個(gè)步驟。

  • 5.1 獲取當(dāng)前線程上下文類(lèi)加載器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

5.2 獲取 `ApplicationContextInitializer 的實(shí)例名稱(chēng)集合并去重

Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));

loadFactoryNames?方法相關(guān)的源碼如下:

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {String factoryClassName = factoryClass.getName();return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}try {Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<?, ?> entry : properties.entrySet()) {List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));result.addAll((String) entry.getKey(), factoryClassNames);}}cache.put(classLoader, result);return result;}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);} }

根據(jù)類(lèi)路徑下的 META-INF/spring.factories 文件解析并獲取 ApplicationContextInitializer 接口的所有配置的類(lèi)路徑名稱(chēng)。

spring-boot-autoconfigure-2.0.3.RELEASE.jar!/META-INF/spring.factories 的初始化器相關(guān)配置內(nèi)容如下:

# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

5.3 根據(jù)以上類(lèi)路徑創(chuàng)建初始化器實(shí)例列表

List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);private <T> List<T> createSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,Set<String> names) {List<T> instances = new ArrayList<>(names.size());for (String name : names) {try {Class<?> instanceClass = ClassUtils.forName(name, classLoader);Assert.isAssignable(type, instanceClass);Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);T instance = (T) BeanUtils.instantiateClass(constructor, args);instances.add(instance);}catch (Throwable ex) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);}}return instances; }

5.4 初始化器實(shí)例列表排序

AnnotationAwareOrderComparator.sort(instances);

5.5 返回初始化器實(shí)例列表

return instances;

6. 設(shè)置監(jiān)聽(tīng)器

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

ApplicationListener?的作用是什么?源碼如下。

@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {/*** Handle an application event.* @param event the event to respond to*/void onApplicationEvent(E event);}

看源碼,這個(gè)接口繼承了 JDK 的 java.util.EventListener 接口,實(shí)現(xiàn)了觀察者模式,它一般用來(lái)定義感興趣的事件類(lèi)型,事件類(lèi)型限定于 ApplicationEvent的子類(lèi),這同樣繼承了 JDK 的 java.util.EventObject 接口。

設(shè)置監(jiān)聽(tīng)器和設(shè)置初始化器調(diào)用的方法是一樣的,只是傳入的類(lèi)型不一樣,設(shè)置監(jiān)聽(tīng)器的接口類(lèi)型為: getSpringFactoriesInstances,對(duì)應(yīng)的 spring-boot-autoconfigure-2.0.3.RELEASE.jar!/META-INF/spring.factories 文件配置內(nèi)容請(qǐng)見(jiàn)下方。

# Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer

可以看出目前只有一個(gè)?BackgroundPreinitializer?監(jiān)聽(tīng)器。
7.推斷主入口應(yīng)用類(lèi)

this.mainApplicationClass = deduceMainApplicationClass();private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();for (StackTraceElement stackTraceElement : stackTrace) {if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}}catch (ClassNotFoundException ex) {// Swallow and continue}return null; }

這個(gè)推斷入口應(yīng)用類(lèi)的方式有點(diǎn)特別,通過(guò)構(gòu)造一個(gè)運(yùn)行時(shí)異常,再遍歷異常棧中的方法名,獲取方法名為 main 的棧幀,從來(lái)得到入口類(lèi)的名字再返回該類(lèi)。

總結(jié)

源碼分析內(nèi)容有點(diǎn)多,也很麻煩,本章暫時(shí)分析到 SpringApplication 構(gòu)造方法的初始化流程,下章再繼續(xù)分析其 run 方法


第二篇

SpringApplication 實(shí)例 run 方法運(yùn)行過(guò)程

上面分析了?SpringApplication?實(shí)例對(duì)象構(gòu)造方法初始化過(guò)程,下面繼續(xù)來(lái)看下這個(gè)?SpringApplication?對(duì)象的?run?方法的源碼和運(yùn)行流程。

public ConfigurableApplicationContext run(String... args) {// 1、創(chuàng)建并啟動(dòng)計(jì)時(shí)監(jiān)控類(lèi)StopWatch stopWatch = new StopWatch();stopWatch.start();// 2、初始化應(yīng)用上下文和異常報(bào)告集合ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();// 3、設(shè)置系統(tǒng)屬性 `java.awt.headless` 的值,默認(rèn)值為:trueconfigureHeadlessProperty();// 4、創(chuàng)建所有 Spring 運(yùn)行監(jiān)聽(tīng)器并發(fā)布應(yīng)用啟動(dòng)事件SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {// 5、初始化默認(rèn)應(yīng)用參數(shù)類(lèi)ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 6、根據(jù)運(yùn)行監(jiān)聽(tīng)器和應(yīng)用參數(shù)來(lái)準(zhǔn)備 Spring 環(huán)境ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);configureIgnoreBeanInfo(environment);// 7、創(chuàng)建 Banner 打印類(lèi)Banner printedBanner = printBanner(environment);// 8、創(chuàng)建應(yīng)用上下文context = createApplicationContext();// 9、準(zhǔn)備異常報(bào)告器exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);// 10、準(zhǔn)備應(yīng)用上下文prepareContext(context, environment, listeners, applicationArguments,printedBanner);// 11、刷新應(yīng)用上下文refreshContext(context);// 12、應(yīng)用上下文刷新后置處理afterRefresh(context, applicationArguments);// 13、停止計(jì)時(shí)監(jiān)控類(lèi)stopWatch.stop();// 14、輸出日志記錄執(zhí)行主類(lèi)名、時(shí)間信息if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// 15、發(fā)布應(yīng)用上下文啟動(dòng)完成事件listeners.started(context);// 16、執(zhí)行所有 Runner 運(yùn)行器callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {// 17、發(fā)布應(yīng)用上下文就緒事件listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}// 18、返回應(yīng)用上下文return context; }

所以,我們可以按以下幾步來(lái)分解?run方法的啟動(dòng)過(guò)程。

1、創(chuàng)建并啟動(dòng)計(jì)時(shí)監(jiān)控類(lèi)

StopWatch stopWatch = new StopWatch(); stopWatch.start();

來(lái)看下這個(gè)計(jì)時(shí)監(jiān)控類(lèi) StopWatch 的相關(guān)源碼:

public void start() throws IllegalStateException {start(""); }public void start(String taskName) throws IllegalStateException {if (this.currentTaskName != null) {throw new IllegalStateException("Can't start StopWatch: it's already running");}this.currentTaskName = taskName;this.startTimeMillis = System.currentTimeMillis(); }

首先記錄了當(dāng)前任務(wù)的名稱(chēng),默認(rèn)為空字符串,然后記錄當(dāng)前 Spring Boot 應(yīng)用啟動(dòng)的開(kāi)始時(shí)間。
2、初始化應(yīng)用上下文和異常報(bào)告集合

ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

3、設(shè)置系統(tǒng)屬性?java.awt.headless?的值

configureHeadlessProperty();

設(shè)置該默認(rèn)值為:true,Java.awt.headless = true 有什么作用?

對(duì)于一個(gè) Java 服務(wù)器來(lái)說(shuō)經(jīng)常要處理一些圖形元素,例如地圖的創(chuàng)建或者圖形和圖表等。這些API基本上總是需要運(yùn)行一個(gè)X-server以便能使用AWT(Abstract Window Toolkit,抽象窗口工具集)。然而運(yùn)行一個(gè)不必要的 X-server 并不是一種好的管理方式。有時(shí)你甚至不能運(yùn)行 X-server,因此最好的方案是運(yùn)行 headless 服務(wù)器,來(lái)進(jìn)行簡(jiǎn)單的圖像處理。

參考:www.cnblogs.com/princessd8251/p/4000016.html

4、創(chuàng)建所有 Spring 運(yùn)行監(jiān)聽(tīng)器并發(fā)布應(yīng)用啟動(dòng)事件
?

SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting();

來(lái)看下創(chuàng)建 Spring 運(yùn)行監(jiān)聽(tīng)器相關(guān)的源碼:

private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }SpringApplicationRunListeners(Log log,Collection<? extends SpringApplicationRunListener> listeners) {this.log = log;this.listeners = new ArrayList<>(listeners); }

創(chuàng)建邏輯和之前實(shí)例化初始化器和監(jiān)聽(tīng)器的一樣,一樣調(diào)用的是 getSpringFactoriesInstances 方法來(lái)獲取配置的監(jiān)聽(tīng)器名稱(chēng)并實(shí)例化所有的類(lèi)。

SpringApplicationRunListener 所有監(jiān)聽(tīng)器配置在 spring-boot-2.0.3.RELEASE.jar!/META-INF/spring.factories 這個(gè)配置文件里面。

# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener

5、初始化默認(rèn)應(yīng)用參數(shù)類(lèi)

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

6、根據(jù)運(yùn)行監(jiān)聽(tīng)器和應(yīng)用參數(shù)來(lái)準(zhǔn)備 Spring 環(huán)境

ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments); configureIgnoreBeanInfo(environment);

下面我們主要來(lái)看下準(zhǔn)備環(huán)境的 prepareEnvironment 源碼:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// 6.1) 獲取(或者創(chuàng)建)應(yīng)用環(huán)境ConfigurableEnvironment environment = getOrCreateEnvironment();// 6.2) 配置應(yīng)用環(huán)境configureEnvironment(environment, applicationArguments.getSourceArgs());listeners.environmentPrepared(environment);bindToSpringApplication(environment);if (this.webApplicationType == WebApplicationType.NONE) {environment = new EnvironmentConverter(getClassLoader()).convertToStandardEnvironmentIfNecessary(environment);}ConfigurationPropertySources.attach(environment);return environment; }

6.1 獲取(或者創(chuàng)建)應(yīng)用環(huán)境

private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {return this.environment;}if (this.webApplicationType == WebApplicationType.SERVLET) {return new StandardServletEnvironment();}return new StandardEnvironment(); }

這里分為標(biāo)準(zhǔn)?Servlet?環(huán)境和標(biāo)準(zhǔn)環(huán)境。

  • 6.2 配置應(yīng)用環(huán)境
protected void configureEnvironment(ConfigurableEnvironment environment,String[] args) {configurePropertySources(environment, args);configureProfiles(environment, args); }

這里分為以下兩步來(lái)配置應(yīng)用環(huán)境。

  • 配置 property sources
  • 配置 Profiles

這里主要處理所有 property sources 配置和 profiles 配置。

7、創(chuàng)建 Banner 打印類(lèi)

Banner printedBanner = printBanner(environment);

這是用來(lái)打印 Banner 的處理類(lèi),這個(gè)沒(méi)什么好說(shuō)的。

8、創(chuàng)建應(yīng)用上下文

context = createApplicationContext();

來(lái)看下?createApplicationContext()?方法的源碼:

protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET:contextClass = Class.forName(DEFAULT_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); }

其實(shí)就是根據(jù)不同的應(yīng)用類(lèi)型初始化不同的上下文應(yīng)用類(lèi)。

9、準(zhǔn)備異常報(bào)告器

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);

邏輯和之前實(shí)例化初始化器和監(jiān)聽(tīng)器的一樣,一樣調(diào)用的是 getSpringFactoriesInstances 方法來(lái)獲取配置的異常類(lèi)名稱(chēng)并實(shí)例化所有的異常處理類(lèi)。

該異常報(bào)告處理類(lèi)配置在 spring-boot-2.0.3.RELEASE.jar!/META-INF/spring.factories 這個(gè)配置文件里面。


?

# Error Reporters org.springframework.boot.SpringBootExceptionReporter=\ org.springframework.boot.diagnostics.FailureAnalyzers

10、準(zhǔn)備應(yīng)用上下文

prepareContext(context, environment, listeners, applicationArguments,printedBanner);

來(lái)看下?prepareContext()?方法的源碼:

private void prepareContext(ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 10.1)綁定環(huán)境到上下文context.setEnvironment(environment);// 10.2)配置上下文的 bean 生成器及資源加載器postProcessApplicationContext(context);// 10.3)為上下文應(yīng)用所有初始化器applyInitializers(context);// 10.4)觸發(fā)所有 SpringApplicationRunListener 監(jiān)聽(tīng)器的 contextPrepared 事件方法listeners.contextPrepared(context);// 10.5)記錄啟動(dòng)日志if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// 10.6)注冊(cè)兩個(gè)特殊的單例beancontext.getBeanFactory().registerSingleton("springApplicationArguments",applicationArguments);if (printedBanner != null) {context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);}// 10.7)加載所有資源Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));// 10.8)觸發(fā)所有 SpringApplicationRunListener 監(jiān)聽(tīng)器的 contextLoaded 事件方法listeners.contextLoaded(context); }

11、刷新應(yīng)用上下文

refreshContext(context);

這個(gè)主要是刷新 Spring 的應(yīng)用上下文,源碼如下,不詳細(xì)說(shuō)明。

private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}} }

這個(gè)主要是刷新 Spring 的應(yīng)用上下文,源碼如下,不詳細(xì)說(shuō)明。

private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}} }

12、應(yīng)用上下文刷新后置處理

afterRefresh(context, applicationArguments);

看了下這個(gè)方法的源碼是空的,目前可以做一些自定義的后置處理操作。

/*** Called after the context has been refreshed.* @param context the application context* @param args the application arguments*/ protected void afterRefresh(ConfigurableApplicationContext context,ApplicationArguments args) { }

13、停止計(jì)時(shí)監(jiān)控類(lèi)

stopWatch.stop(); public void stop() throws IllegalStateException {if (this.currentTaskName == null) {throw new IllegalStateException("Can't stop StopWatch: it's not running");}long lastTime = System.currentTimeMillis() - this.startTimeMillis;this.totalTimeMillis += lastTime;this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);if (this.keepTaskList) {this.taskList.add(this.lastTaskInfo);}++this.taskCount;this.currentTaskName = null; } ```java 計(jì)時(shí)監(jiān)聽(tīng)器停止,并統(tǒng)計(jì)一些任務(wù)執(zhí)行信息。**14、輸出日志記錄執(zhí)行主類(lèi)名、時(shí)間信息** ```java if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); }

15、發(fā)布應(yīng)用上下文啟動(dòng)完成事件

listeners.started(context);

觸發(fā)所有?SpringApplicationRunListener?監(jiān)聽(tīng)器的?started?事件方法。

16、執(zhí)行所有 Runner 運(yùn)行器

callRunners(context, applicationArguments); 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);}} }

執(zhí)行所有 ApplicationRunner 和 CommandLineRunner 這兩種運(yùn)行器,不詳細(xì)展開(kāi)了。

17、發(fā)布應(yīng)用上下文就緒事件
listeners.running(context);
觸發(fā)所有 SpringApplicationRunListener 監(jiān)聽(tīng)器的 running 事件方法。

18、返回應(yīng)用上下文
?

return context;

?

總結(jié)

Spring Boot 的啟動(dòng)全過(guò)程源碼分析至此,分析 Spring 源碼真是一個(gè)痛苦的過(guò)程,希望能給大家提供一點(diǎn)參考和思路,也希望能給正在 Spring Boot 學(xué)習(xí)路上的朋友一點(diǎn)收獲。

?

總結(jié)

以上是生活随笔為你收集整理的SpringBoot2.x启动原理概述的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。