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

歡迎訪問 生活随笔!

生活随笔

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

javascript

Spring Boot 2.x 启动全过程源码分析(全)

發(fā)布時(shí)間:2025/3/21 javascript 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Boot 2.x 启动全过程源码分析(全) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上篇《Spring Boot 2.x 啟動(dòng)全過(guò)程源碼分析(一)入口類剖析》我們分析了 Spring Boot 入口類 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)控類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)聽器并發(fā)布應(yīng)用啟動(dòng)事件SpringApplicationRunListeners?listeners?=?getRunListeners(args);listeners.starting();try?{//?5、初始化默認(rèn)應(yīng)用參數(shù)類ApplicationArguments?applicationArguments?=?new?DefaultApplicationArguments(args);//?6、根據(jù)運(yùn)行監(jiān)聽器和應(yīng)用參數(shù)來(lái)準(zhǔn)備?Spring?環(huán)境ConfigurableEnvironment?environment?=?prepareEnvironment(listeners,applicationArguments);configureIgnoreBeanInfo(environment);//?7、創(chuàng)建?Banner?打印類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)控類stopWatch.stop();//?14、輸出日志記錄執(zhí)行主類名、時(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)控類

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

來(lái)看下這個(gè)計(jì)時(shí)監(jiān)控類 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ù)的名稱,默認(rèn)為空字符串,然后記錄當(dāng)前 Spring Boot 應(yīng)用啟動(dòng)的開始時(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)聽器并發(fā)布應(yīng)用啟動(dòng)事件

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

來(lái)看下創(chuàng)建 Spring 運(yùn)行監(jiān)聽器相關(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)聽器的一樣,一樣調(diào)用的是?getSpringFactoriesInstances?方法來(lái)獲取配置的監(jiān)聽器名稱并實(shí)例化所有的類。

SpringApplicationRunListener 所有監(jiān)聽器配置在?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ù)類

ApplicationArguments?applicationArguments?=?new?DefaultApplicationArguments(args);

6、根據(jù)運(yùn)行監(jiān)聽器和應(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 打印類

Banner?printedBanner?=?printBanner(environment);

這是用來(lái)打印 Banner 的處理類,這個(gè)沒什么好說(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)用類型初始化不同的上下文應(yīng)用類。

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

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

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

該異常報(bào)告處理類配置在?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)聽器的?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)聽器的?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.}} }

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)控類

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

計(jì)時(shí)監(jiān)聽器停止,并統(tǒng)計(jì)一些任務(wù)執(zhí)行信息。

14、輸出日志記錄執(zhí)行主類名、時(shí)間信息

if?(this.logStartupInfo)?{new?StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(),?stopWatch); }

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

listeners.started(context);

觸發(fā)所有 SpringApplicationRunListener 監(jiān)聽器的 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ì)展開了。

17、發(fā)布應(yīng)用上下文就緒事件

listeners.running(context);

觸發(fā)所有 SpringApplicationRunListener 監(jiān)聽器的 running 事件方法。

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

return?context;

總結(jié)

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

總結(jié)

以上是生活随笔為你收集整理的Spring Boot 2.x 启动全过程源码分析(全)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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