javascript
厉害了!SpringBoot是如何动起来的!
作者:襄垣
juejin.im/post/5c6f730ce51d457f14363a53
程序入口
SpringApplication.run(BeautyApplication.class,?args);執行此方法來加載整個SpringBoot的環境。
1. 從哪兒開始?
SpringApplication.java
????/***?Run?the?Spring?application,?creating?and?refreshing?a?new*?{@link?ApplicationContext}.*?@param?args?the?application?arguments?(usually?passed?from?a?Java?main?method)*?@return?a?running?{@link?ApplicationContext}*/public?ConfigurableApplicationContext?run(String...?args)?{//...}調用SpringApplication.java 中的 run 方法,目的是加載Spring Application,同時返回 ApplicationContext。
2. 執行了什么?
2.1 計時
記錄整個Spring Application的加載時間!
StopWatch?stopWatch?=?new?StopWatch(); stopWatch.start(); //?... stopWatch.stop(); if?(this.logStartupInfo)?{new?StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(),?stopWatch); }2.2 聲明
//?聲明?ApplicationContext ConfigurableApplicationContext?context?=?null; //?聲明?一個異常報告集合 Collection<SpringBootExceptionReporter>?exceptionReporters?=?new?ArrayList<>();2.3 指定程序運行模式
指定 java.awt.headless,默認是true 一般是在程序開始激活headless模式,告訴程序,現在你要工作在Headless mode下,就不要指望硬件幫忙了,你得自力更生,依靠系統的計算能力模擬出這些特性來。
private?void?configureHeadlessProperty()?{System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,?System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,?Boolean.toString(this.headless))); }2.4 配置監聽并發布應用啟動事件
SpringApplicationRunListener 負責加載 ApplicationListener事件。
SpringApplicationRunListeners?listeners?=?getRunListeners(args); //?開始 listeners.starting(); //?處理所有?property?sources?配置和?profiles?配置,準備環境,分為標準?Servlet?環境和標準環境 ConfigurableEnvironment?environment?=?prepareEnvironment(listeners,applicationArguments); //?準備應用上下文 prepareContext(context,?environment,?listeners,?applicationArguments,printedBanner); //?完成 listeners.started(context); //?異常 handleRunFailure(context,?ex,?exceptionReporters,?listeners); //?執行 listeners.running(context);getRunListeners 中根據 type = SpringApplicationRunListener.class 去拿到了所有的 Listener 并根據優先級排序。
對應的就是 META-INF/spring.factories 文件中的 org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener
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;}在 ApplicationListener 中 , 可以針對任何一個階段插入處理代碼。
public?interface?SpringApplicationRunListener?{/***?Called?immediately?when?the?run?method?has?first?started.?Can?be?used?for?very*?early?initialization.*/void?starting();/***?Called?once?the?environment?has?been?prepared,?but?before?the*?{@link?ApplicationContext}?has?been?created.*?@param?environment?the?environment*/void?environmentPrepared(ConfigurableEnvironment?environment);/***?Called?once?the?{@link?ApplicationContext}?has?been?created?and?prepared,?but*?before?sources?have?been?loaded.*?@param?context?the?application?context*/void?contextPrepared(ConfigurableApplicationContext?context);/***?Called?once?the?application?context?has?been?loaded?but?before?it?has?been*?refreshed.*?@param?context?the?application?context*/void?contextLoaded(ConfigurableApplicationContext?context);/***?The?context?has?been?refreshed?and?the?application?has?started?but*?{@link?CommandLineRunner?CommandLineRunners}?and?{@link?ApplicationRunner*?ApplicationRunners}?have?not?been?called.*?@param?context?the?application?context.*?@since?2.0.0*/void?started(ConfigurableApplicationContext?context);/***?Called?immediately?before?the?run?method?finishes,?when?the?application?context?has*?been?refreshed?and?all?{@link?CommandLineRunner?CommandLineRunners}?and*?{@link?ApplicationRunner?ApplicationRunners}?have?been?called.*?@param?context?the?application?context.*?@since?2.0.0*/void?running(ConfigurableApplicationContext?context);/***?Called?when?a?failure?occurs?when?running?the?application.*?@param?context?the?application?context?or?{@code?null}?if?a?failure?occurred?before*?the?context?was?created*?@param?exception?the?failure*?@since?2.0.0*/void?failed(ConfigurableApplicationContext?context,?Throwable?exception);}3. 每個階段執行的內容
3.1 listeners.starting();
在加載Spring Application之前執行,所有資源和環境未被加載。
3.2 prepareEnvironment(listeners, applicationArguments);
創建 ConfigurableEnvironment;將配置的環境綁定到Spring Application中;
????private?ConfigurableEnvironment?prepareEnvironment(SpringApplicationRunListeners?listeners,ApplicationArguments?applicationArguments)?{//?Create?and?configure?the?environmentConfigurableEnvironment?environment?=?getOrCreateEnvironment();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;}3.3 prepareContext
配置忽略的Bean;
????private?void?configureIgnoreBeanInfo(ConfigurableEnvironment?environment)?{if?(System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME)?==?null)?{Boolean?ignore?=?environment.getProperty("spring.beaninfo.ignore",Boolean.class,?Boolean.TRUE);System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,ignore.toString());}}打印日志-加載的資源
Banner?printedBanner?=?printBanner(environment);根據不同的WebApplicationType創建Context
context?=?createApplicationContext();3.4 refreshContext
支持定制刷新
????/***?Register?a?shutdown?hook?with?the?JVM?runtime,?closing?this?context*?on?JVM?shutdown?unless?it?has?already?been?closed?at?that?time.*?<p>This?method?can?be?called?multiple?times.?Only?one?shutdown?hook*?(at?max)?will?be?registered?for?each?context?instance.*?@see?java.lang.Runtime#addShutdownHook*?@see?#close()*/void?registerShutdownHook();3.5 afterRefresh
刷新后的實現方法暫未實現
????/***?Called?after?the?context?has?been?refreshed.*?@param?context?the?application?context*?@param?args?the?application?arguments*/protected?void?afterRefresh(ConfigurableApplicationContext?context,ApplicationArguments?args)?{}3.6 listeners.started(context);
到此為止, Spring Application的環境和資源都加載完畢了;發布應用上下文啟動完成事件;執行所有 Runner 運行器 - 執行所有 ApplicationRunner 和 CommandLineRunner 這兩種運行器。
//?啟動 callRunners(context,?applicationArguments);3.7 listeners.running(context);
觸發所有 SpringApplicationRunListener 監聽器的 running 事件方法
總結
以上是生活随笔為你收集整理的厉害了!SpringBoot是如何动起来的!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详解 Java 的八大基本类型,写得非常
- 下一篇: 3种骚操作,教你查看 Java 字节码!