1. 程式人生 > >springboot啟動流程分析(一)

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