深度挖掘SpringBoot

new SpringApplication()創建實例

​ Create a new {@link SpringApplication} instance

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    
  WebApplicationType.deduceFromClasspath();
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   this.mainApplicationClass = deduceMainApplicationClass();
}

實例化SpringApplication流程

  • 推斷web類型(SERVLET)
  • 設置ApplicationContextInitializer
    • 利用工廠加載機制實例化ApplicationContextInitializer的子類
  • 設置ApplicationListener監聽類
  • 推到main方法運行的主類

工廠加載機制SpringFactoriesLoader

介紹

  • 框架內部通用工廠加載機制
  • 從classpath下多個jar包特定的位置讀取文件並初始化類
  • 文件內容必須k-v形式,即properties類型
  • key是全限定名(抽象類|接口)、value是實現、多個實現,分割
SpringApplication.getSpringFactoriesInstances(Xxxx.class);
	1.實例化EventPublishingRunListener
//工廠加載機制
SpringFactoriesLoader.loadFactoryNames()

加載流程圖

在這裏插入圖片描述


框架啓動方法run()

框架啓動流程

計時器Headless模式賦值發送ApplicationStartingEvent配置環境模塊打印banner創建應用上下文對象初始化失敗分析器關聯springboot組件與應用上下文對象發送ApplicationContextInitializedEvent加載sources到context發送ApplicationPreparedEvent刷新上下文計時器停止計時發送ApplicationContextStartedEvent調用框架啓動擴展類==》發送ApplicationReadyEvent

系統初始化器解析ApplicationContextInitializer

在這裏插入圖片描述

調用順序

  • //應用準備階段
    prepareContext();
    //spring中刷新上下文的核心方法
    refreshContext(context);
    //
    prepareContext(){
        ...
        applyInitializers();
        ...
    }
    

​ 加載spring.factories中註冊在ApplicationContextInitializer初始化類

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

調用模板類ApplicationContextInitializer.initialize()方法,完成初始化。

實現步驟:

1.實現ApplicationContextInitializer接口

2.spring.factories內填寫接口實現


SpringBoot監聽器解析

監聽器模式介紹

  • 事件
  • 監聽器
  • 廣播器
  • 觸發機制

系統監聽器介紹ApplicationListener

  • 事件

    ApplicationEvent
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-X9sPJo9l-1593612510738)(C:\Users\ACER\AppData\Roaming\Typora\typora-user-images\image-20200629190925223.png)]

  • 監聽器

    interface ApplicationListener
    
  • 廣播器

    interface ApplicationEventMulticaster
    

監聽器註冊

​ 同上系統初始化註冊,通過SpringFactories.loadFactoryNames()加載配置在spring.factories中的ApplicationListener.class的實現類

監聽事件觸發機制

在這裏插入圖片描述
​ ***以run()中的SpringApplicationRunListener爲例子

  • SpringApplicationRunListeners listeners = getRunListeners(args);

  • listeners.starting(); //SpringApplicationRunListener的集合

    • listener.starting(); //開啓入口,實現在EventPublishingRunListener
@Override
public void starting() {
   this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
//由事件廣播發布ApplicationStartingEvent事件	
//event:事件本身,eventType:shiji
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   Executor executor = getTaskExecutor();
    
    //根據事件獲取對應的監聽對象getApplicationListeners()
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
          //觸發監聽器
         invokeListener(listener, event);
      }
   }
}

​ ResolvableType代表事件的類型解析,ApplicationEvent代表事件本身

1.獲取監聽getApplicationListeners(ApplicationEvent event, ResolvableType eventType)

  1. 緩存中查找監聽 this.retrieverCache.get(cacheKey)
  2. 檢索出所有的感興趣的監聽 retrieveApplicationListeners(eventType, sourceType, retriever);
1.1監聽檢索retrieveApplicationListeners()

在這裏插入圖片描述

​ 1.1.1加載所有監聽

​ 1.1.2遍歷監聽,篩選出對事件感興趣的監聽supportsEvent(listener, eventType, sourceType);

​ listener intanceof GenericApplicationListener;不屬於則使用適配器轉換爲GenericApplicationListener類型,最後判斷是否支持事件來判斷是否感興趣,後面的一個判斷一般爲true; (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType))

​ 1.1.3將感興趣的監聽加入到監聽檢索ListenerRetriever中。

​ 1.1.4監聽排序

1.2將監聽加入到索引緩存retrieverCache

2.調用監聽invokeListener()

  1. 調用ApplicationListener中唯一的監聽調用方法listener.onApplicationEvent(event);

SpringBoot Banner

​ 配置文件配置banner的位置

banner獲取原理

run方法代碼入口: Banner printedBanner = printBanner(environment);
核心類:資源加載ResourceLoader、banner包裝Banner、輸出PrintStream

計時器

run方法代碼入口
StopWatch stopWatch = new StopWatch();
stopWatch.start();
stopWatch.stop();

啓動加載器

​ 可以在springboot啓動後加載。

run方法代碼入口:callRunners(context, applicationArguments);

方法實現方式

  • 添加ApplicationRunner實現至runners中
  • 添加CommondLineRunner實現至runners中
  • 對runners集合排序
  • 遍歷調用實現類的run方法

自定義實現方式

  • 繼承實現CommandLineRunner
  • 繼承實現ApplicationRunner

面試題

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章