前言
成都創(chuàng)新互聯(lián)公司專注于臨桂網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供臨桂營(yíng)銷型網(wǎng)站建設(shè),臨桂網(wǎng)站制作、臨桂網(wǎng)頁(yè)設(shè)計(jì)、臨桂網(wǎng)站官網(wǎng)定制、微信小程序開發(fā)服務(wù),打造臨桂網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供臨桂網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。
前一篇分析了SpringBoot如何啟動(dòng)以及內(nèi)置web容器,這篇我們一起看一下SpringBoot的整個(gè)啟動(dòng)過(guò)程,廢話不多說(shuō),正文開始。
正文
一、SpringBoot的啟動(dòng)類是**application,以注解@SpringBootApplication注明。
@SpringBootApplication public class CmsApplication { public static void main(String[] args) { SpringApplication.run(CmsApplication.class, args); } }
SpringBootApplication注解是@Configuration,@EnableAutoConfiguration,@ComponentScan三個(gè)注解的集成,分別表示Springbean的配置bean,開啟自動(dòng)配置spring的上下文,組件掃描的路徑,這也是為什么*application.java需要放在根路徑的原因,這樣@ComponentScan掃描的才是整個(gè)項(xiàng)目。
二、該啟動(dòng)類默認(rèn)只有一個(gè)main方法,調(diào)用的是SpringApplication.run方法,下面我們來(lái)看一下SpringApplication這個(gè)類。
public static ConfigurableApplicationContext run(Object source, String... args) { return run(new Object[]{source}, args); } ... public static ConfigurableApplicationContext run(Object[] sources, String[] args) { return (new SpringApplication(sources)).run(args);//sources為具體的CmsApplication.class類 } ...
抽出其中兩個(gè)直接調(diào)用的run方法,可以看出靜態(tài)方法SpringApplication.run最終創(chuàng)建了一個(gè)SpringApplication,并運(yùn)行其中run方法。
查看起構(gòu)造方法:
public SpringApplication(Object... sources) { this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.initialize(sources); } ...
構(gòu)造方法設(shè)置了基礎(chǔ)值后調(diào)用initialize方法進(jìn)行初始化,如下:
private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = this.deduceWebEnvironment(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); } ...
初始化方法主要做了幾步:
1.將source放入SpringApplication的sources屬性中管理,sources是一個(gè)LinkedHashSet()
,這意味著我們可以同時(shí)創(chuàng)建多個(gè)自定義不重復(fù)的Application,但是目前只有一個(gè)。
2.判斷是否是web程序(javax.servlet.Servlet
和org.springframework.web.context.ConfigurableWebApplicationContext
都必須在類加載器中存在),并設(shè)置到webEnvironment
屬性中。
3.從spring.factories中找出ApplicationContextInitializer并設(shè)置到初始化器initializers。
4.從spring.factories中找出ApplicationListener,并實(shí)例化后設(shè)置到SpringApplication的監(jiān)聽器listeners屬性中。這個(gè)過(guò)程就是找出所有的應(yīng)用程序事件監(jiān)聽器。
5.找出的main方法的類(這里是CmsApplication),并返回Class對(duì)象。
默認(rèn)情況下,initialize方法從spring.factories文件中找出的key為ApplicationContextInitializer的類有:
key為ApplicationListener的有:
三、SpringApplication構(gòu)造和初始化完成后,便是運(yùn)行其run方法
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch();// 構(gòu)造一個(gè)任務(wù)執(zhí)行觀察器 stopWatch.start();// 開始執(zhí)行,記錄開始時(shí)間 ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; this.configureHeadlessProperty(); // 獲取SpringApplicationRunListeners,內(nèi)部只有一個(gè)EventPublishingRunListener SpringApplicationRunListeners listeners = this.getRunListeners(args); // 封裝成SpringApplicationEvent事件然后廣播出去給SpringApplication中的listeners所監(jiān)聽,啟動(dòng)監(jiān)聽 listeners.starting(); try { // 構(gòu)造一個(gè)應(yīng)用程序參數(shù)持有類 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 加載配置環(huán)境 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); Banner printedBanner = this.printBanner(environment); // 創(chuàng)建Spring容器(使用BeanUtils.instantiate) context = this.createApplicationContext(); // 若容器創(chuàng)建失敗,分析輸出失敗原因 new FailureAnalyzers(context); // 設(shè)置容器配置環(huán)境,監(jiān)聽等 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新容器 this.refreshContext(context); this.afterRefresh(context, applicationArguments); // 廣播出ApplicationReadyEvent事件給相應(yīng)的監(jiān)聽器執(zhí)行 listeners.finished(context, (Throwable)null); stopWatch.stop();// 執(zhí)行結(jié)束,記錄執(zhí)行時(shí)間 if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } return context;// 返回Spring容器 } catch (Throwable var9) { this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9); throw new IllegalStateException(var9); } }
run方法過(guò)程分析如上,該方法幾個(gè)關(guān)鍵步驟如下:
1.創(chuàng)建了應(yīng)用的監(jiān)聽器SpringApplicationRunListeners并開始監(jiān)聽
2.加載SpringBoot配置環(huán)境(ConfigurableEnvironment),如果是通過(guò)web容器發(fā)布,會(huì)加載StandardEnvironment,其最終也是繼承了ConfigurableEnvironment,類圖如下
可以看出,*Environment最終都實(shí)現(xiàn)了PropertyResolver接口,我們平時(shí)通過(guò)environment對(duì)象獲取配置文件中指定Key對(duì)應(yīng)的value方法時(shí),就是調(diào)用了propertyResolver接口的getProperty方法。
3.配置環(huán)境(Environment)加入到監(jiān)聽器對(duì)象中(SpringApplicationRunListeners)
4.創(chuàng)建Spring容器:ConfigurableApplicationContext(應(yīng)用配置上下文),我們可以看一下創(chuàng)建方法
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { contextClass = Class.forName(this.webEnvironment ? "org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext" : "org.springframework.context.annotation.AnnotationConfigApplicationContext"); } catch (ClassNotFoundException var3) { throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3); } } return (ConfigurableApplicationContext)BeanUtils.instantiate(contextClass); }
方法會(huì)先獲取顯式設(shè)置的應(yīng)用上下文(applicationContextClass),如果不存在,再加載默認(rèn)的環(huán)境配置(通過(guò)是否是web environment判斷),默認(rèn)選擇AnnotationConfigApplicationContext注解上下文(通過(guò)掃描所有注解類來(lái)加載bean),最后通過(guò)BeanUtils實(shí)例化上下文對(duì)象,并返回,ConfigurableApplicationContext類圖如下
主要看其繼承的兩個(gè)方向:
5.回到run方法內(nèi),設(shè)置容器prepareContext方法,將listeners、environment、applicationArguments、banner等重要組件與上下文對(duì)象關(guān)聯(lián)
6.刷新容器,refresh()
方法,初始化方法如下:
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); try { this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
refresh()
方法做了很多核心工作比如BeanFactory的設(shè)置,BeanFactoryPostProcessor接口的執(zhí)行、BeanPostProcessor接口的執(zhí)行、自動(dòng)化配置類的解析、spring.factories的加載、bean的實(shí)例化、條件注解的解析、國(guó)際化的初始化等等。這部分內(nèi)容會(huì)在之后的文章中分析。
7.廣播出ApplicationReadyEvent,執(zhí)行結(jié)束返回ConfigurableApplicationContext。
至此,SpringBoot啟動(dòng)完成,回顧整體流程,Springboot的啟動(dòng),主要?jiǎng)?chuàng)建了配置環(huán)境(environment)、事件監(jiān)聽(listeners)、應(yīng)用上下文(applicationContext),并基于以上條件,在容器中開始實(shí)例化我們需要的Bean。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
本文題目:SpringBoot整個(gè)啟動(dòng)過(guò)程的分析
本文路徑:http://www.chinadenli.net/article16/joiddg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、網(wǎng)站設(shè)計(jì)、動(dòng)態(tài)網(wǎng)站、面包屑導(dǎo)航、外貿(mào)建站、品牌網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)