springboot啟動流程分析(一)
以springboot 2.0.2.RELEASE版本為例
1.pom.xml引入依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
2.檢視啟動入口類:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringdemoApplication {
public static void main(String[] args) {
System.out.println("Service start"); // 自己新增的標記,最開始執行
SpringApplication.run(SpringdemoApplication.class, args);
System.out.println("Service end"); // 自己新增的標記,最後執行
}
}
3.檢視@SpringBootApplication註解
// 註解的適用範圍,其中TYPE用於描述類、介面(包括包註解型別)或enum宣告
@Target(ElementType.TYPE)
// 註解的生命週期,保留到class檔案中(三個生命週期)
@Retention(RetentionPolicy.RUNTIME)
// 表明這個註解應該被javadoc記錄
@Documented
// 子類可以繼承該註解
@Inherited
// 繼承了Configuration,表示當前是註解類
@SpringBootConfiguration
// 開啟springboot的註解功能,springboot的四大神器之一,其藉助@import的幫助
@EnableAutoConfiguration
// 掃描路徑設定(具體使用待確認)
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
4.執行main入口函式,首先會列印之前新增的:”Service start”
5.進入該函式執行:
// 會有兩個引數:
// 引數1:初始化一個SpringApplication物件,將入口類作為springboot的初始化引數
// 引數2:args入參,不設定的時候為空:{}
SpringApplication.run(SpringdemoApplication.class, args);
6.進入該run函式,如下:
// (1)、入口run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
// args={},primarySource=SpringdemoApplication.class
// (2)將primarySource封裝為陣列傳遞,呼叫下一個run方法
return run(new Class[]{primarySource}, args);
}
// (3)下一個run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
(4)呼叫SpringApplication的建構函式例項化,例項化後再執行該類的run方法
return (new SpringApplication(primarySources)).run(args);
}
7.檢視SpringApplication的建構函式:
public SpringApplication(Class<?>... primarySources) {
// this為呼叫本類中的另一個建構函式
this(null, primarySources);
}
8.另一個建構函式如下:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader; // 傳入為空
// 判斷是否有入口類
Assert.notNull(primarySources, "PrimarySources must not be null");
// 轉化為元素插入的順序來維護集合的連結表
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推斷當前環境是什麼環境:Servlet、Reactive、或者不是web環境,判斷邏輯是classpath中的類?????? 比如win10下這個值是SERVELET
this.webApplicationType = deduceWebApplicationType();
// 初始化器initializers:這些初始化器(initializers)是Spring Boot通過讀取每個jar包下的/META-INF/spring.factories檔案中的配置獲取的。每一個initailizer都是一個實現了ApplicationContextInitializer介面的例項。ApplicationContextInitializer是Spring IOC(控制反轉)容器中提供的一個介面:
//【特別要注意的是,這塊的掃描結果,是為了run方法中的prepareContext和refreshContext函式初始化的,參見:https://www.cnblogs.com/hzhuxin/p/7742365.html】
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 監聽器listeners:從spring.factories檔案中找出key為ApplicationListener的類並例項化後設置到SpringApplication的listeners屬性中。這個過程就是找出所有的應用程式事件監聽器
// 【參見:https://blog.csdn.net/Bob_666/article/details/79715156】
setListeners((Collection)
// 該方法獲取執行型別子類例項集合,不太明白????????????????
getSpringFactoriesInstances(ApplicationListener.class));
// 獲取當前呼叫棧,找到入口方法main所在的類,並將其複製給SpringApplication物件的成員變數mainApplicationClass
this.mainApplicationClass = deduceMainApplicationClass();
}
9.開始執行run方法【具體的run方法,待後續】:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();# 任務時間監聽器啟動
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 核心點:會列印springboot的啟動標誌,直到server.port埠啟動
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
// 會呼叫各種Runners進行操作
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
10.Runners操作:
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());
// 這裡的時候,runners就會得到各種實現了CommandLineRunner的類
AnnotationAwareOrderComparator.sort(runners); # 會根據order對runner排序
// 依次遍歷runner,並將其中的值取出來,執行run方法
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
} # 這裡runner實際上是為使用者提供了兩種開機後啟動的程式程式碼
相關推薦
springboot啟動流程分析(一)
以springboot 2.0.2.RELEASE版本為例 1.pom.xml引入依賴 <parent> <groupId>org.springframework.boot</groupId>
SpringBoot啟動流程分析(一):SpringApplication類初始化過程
SpringBoot系列文章簡介 SpringBoot原始碼閱讀輔助篇: Spring IoC容器與應用上下文的設計與實現 SpringBoot啟動流程原始碼分析: SpringBoot啟動流程分析(一):SpringApplication類初始化過程 SpringBoot啟動流程分析(二)
Android9.0 Activity啟動流程分析(一)
1、ActivityRecord、TaskRecord、ActivityStack和ActivityDisplay介紹 本篇文章是基於Android refs/tags/android-9.0.0_r8分支的程式碼進行分析的 在分析Activity啟動的原始碼之前先介紹一下Act
ContentProvider啟動流程分析(一)
## 0x01 扯東扯西的前言&概述 作為安卓設計的四大元件之一,是跨程序共享資料的一把利器,所謂跨程序共享資料,通俗理解就是,應用程式A可以訪問操作應用程式B共享出來的資料,這些共享出來的資料一般都有其對應的URI(統一資源識別符號),那麼就涉及到兩個過程: 提供資料內容的過程: A應用(
springboot啟動流程分析(二)
現在繼續看啟動過程的詳情,詳細描述下SpringApplication建構函式: 1.載入過程中的SpringApplication初始化如下: public SpringApplication(ResourceLoader resourceLoader
SpringBoot啟動流程分析(二):SpringApplication的run方法
SpringBoot系列文章簡介 SpringBoot原始碼閱讀輔助篇: Spring IoC容器與應用上下文的設計與實現 SpringBoot啟動流程原始碼分析: SpringBoot啟動流程分析(一):SpringApplication類初始化過程 SpringBoot啟動流程分析(二)
SpringBoot啟動流程分析(四):IoC容器的初始化過程
SpringBoot系列文章簡介 SpringBoot原始碼閱讀輔助篇: Spring IoC容器與應用上下文的設計與實現 SpringBoot啟動流程原始碼分析: SpringBoot啟動流程分析(一):SpringApplication類初始化過程 SpringBoot啟動流程分析(二)
SpringBoot啟動流程分析(五):SpringBoot自動裝配原理實現
SpringBoot系列文章簡介 SpringBoot原始碼閱讀輔助篇: Spring IoC容器與應用上下文的設計與實現 SpringBoot啟動流程原始碼分析: SpringBoot啟動流程分析(一):SpringApplication類初始化過程 SpringBoot啟動流程分析(二)
SpringBoot啟動流程分析(六):IoC容器依賴注入
SpringBoot系列文章簡介 SpringBoot原始碼閱讀輔助篇: Spring IoC容器與應用上下文的設計與實現 SpringBoot啟動流程原始碼分析: SpringBoot啟動流程分析(一):SpringApplication類初始化過程 SpringBoot啟動流程分析(二)
SpringMVC的流程分析(一)—— 整體流程概括
classes amp 不同 方法 restfu equals 類圖 strong .get SpringMVC的整體概括 之前也寫過springmvc的流程分析,只是當時理解的還不透徹所以那篇文章就放棄了,現在比之前好了些,想著寫下來分享下,也能增強記憶,也希望可以幫助到
Android9.0 Activity啟動流程分析(二)
文章目錄 1、ActivityThread的main函式 2. AMS的attachApplication函式 2.1 Part-I 2.2 Part-II 2.2.1 ApplicationThread的bindApp
Web前端(一)-Vue專案執行流程分析(一)
去年年底離職了創業去了哈,把寫部落格的事情給落下了! 一直盯著專案幾乎很少休息,一個月能休息一天算好的啦,煎熬將近一年啊。 都說 “離職窮半年,創業窮三年”,終於嚐到其中滋味!哎。。。現在終於涼了!哈哈! 最近靜下心來,好好反思總結,其中寫部落格這件事,還是不能停止..
Vue框架專案實戰整理:3、Vue專案執行流程分析(一)
宣告:本教程不收取任何費用,歡迎轉載,尊重作者勞動成果,不得用於商業用途,侵權必究!!!! 上兩篇講了Vue框架專案實戰整理:1、快速啟動Vue、開發工具介紹 和 Vue框架專案實戰整理:2、Vue環境搭建,今天應該到Vue專案執行流程分析的時候了,為什麼會有這方便的研究
dart 非同步事件執行流程分析(一)
深入研究了dart 的非同步事件執行流程。 main() { /// testNoAwait() and testWithCallerAwait() exe order is same. // testNoAwait(); // testWithCal
[Android6.0][RK3399] 雙屏異顯程式碼實現流程分析(一)
Platform: RK3399 OS: Android 6.0 Version: v2016.08 本文分為兩部分。 《[RK3399] 雙屏異顯程式碼實現流程分析(一)》為分析 RK video 部分標準的程式碼(base on 2017.
ContentProvider啟動流程分析(三)
## 0x01 扯東扯西的前言&概述 ## 0x02 ContentProvider啟動流程分析 step15: ApplicationThread#bindApplication() 上一步,在ApplicationThreadProxy類的bindApplication()函式中,通過B
ContentProvider啟動流程分析(二)
## 0x01 扯東扯西的前言&概述 ## 0x02 ContentProvider啟動流程分析 step6: ActivityManagerProxy#getContentProvider() 代理類ActivityManagerProxy位於ActivityManagerNative.j
Android OTA升級原理和流程分析(一)
這篇及以後的篇幅將通過分析update.zip包在具體Android系統升級的過程,來理解Android系統中Recovery模式服務的工作原理。我們先從update.zip包的製作開始,然後是Android系統的啟動模式分析,Recovery工作原理,如何從
Activity啟動流程筆記(一)
從startActivity開始說起: public void startActivity(Intent intent, Bundle options) { if (options != null) { startA
STM32 eCos 啟動程式碼分析(一)系統復位
概述 最近接觸了STM32,開始瞭解CortexM3系列ARM處理器上RTOS的移植和啟動。 開始總是艱難的,CortexM3是arm7tdmi的升級產品,但實際上和之前的ARM7有著很大的區別。 首先,我們必須有支援CortexM3的編譯器,因為CortexM3採用的是T