從零玩轉系列之SpringBoot3-核心原理

来源:https://www.cnblogs.com/Yangbuyi/archive/2023/07/14/17555076.html
-Advertisement-
Play Games

# 一、簡介 ## 1.前置知識 ● Java17 ● Spring、SpringMVC、MyBatis ● Maven、IDEA ## 2.環境要求 | 環境&工具 | 版本(or later) | | : : | : : | | SpringBoot | 3.1.x | | IDEA | 202 ...


一、簡介

1.前置知識

● Java17
● Spring、SpringMVC、MyBatis
● Maven、IDEA

2.環境要求

環境&工具 版本(or later)
SpringBoot 3.1.x
IDEA 2023.x
Java 17+
Maven 3.5+
Tomcat 10.0+
Servlet 5.0+
GraalVM Community 22.3+
Native Build Tools 0.9.19+

二、SpringBoot3-核心原理

1.事件和監聽器

1.1. 生命周期監聽

1.2. 監聽器-SpringApplicationRunListener

  • 自定義SpringApplicationRunListener監聽事件
  • 編寫SpringApplicationRunListener 實現類
    • **在 META-INF/spring.factories 中配置 org.springframework.boot.SpringApplicationRunListener=自己的Listener,還可以指定一個 有參構造器 ,接受兩個參數(SpringApplication application, String[] args)
    • springboot 在spring-boot.jar中配置了預設的 Listener,如下

輸入圖片說明

輸入圖片說明

2. 生命周期

/**
 * Listener先要從 META-INF/spring.factories 讀到
 *
 * 1、引導: 利用 BootstrapContext 引導整個項目啟動
 *      starting:              應用開始,SpringApplication的run方法一調用,只要有了 BootstrapContext 就執行
 *      environmentPrepared:   環境準備好(把啟動參數等綁定到環境變數中),但是ioc還沒有創建;【調一次】
 * 2、啟動:
 *      contextPrepared:       ioc容器創建並準備好,但是sources(主配置類)沒載入。並關閉引導上下文;組件都沒創建  【調一次】
 *      contextLoaded:         ioc容器載入。主配置類載入進去了。但是ioc容器還沒刷新(我們的bean沒創建)。
 *      =======截止以前,ioc容器裡面還沒造bean呢=======
 *      started:               ioc容器刷新了(所有bean造好了),但是 runner 沒調用。
 *      ready:                  ioc容器刷新了(所有bean造好了),所有 runner 調用完了。
 * 3、運行
 *     以前步驟都正確執行,代表容器running。
 */

3.事件觸發時機

1. 各種回調監聽器

  • BootstrapRegistryInitializer感知特定階段:感知引導初始化

    • META-INF/spring.factories
    • 創建引導上下文bootstrapContext的時候觸發。
    • application.addBootstrapRegistryInitializer();
    • 場景:進行密鑰校對授權。
  • ApplicationContextInitializer: 感知特定階段: 感知ioc容器初始化

    • META-INF/spring.factories
    • application.addInitializers();
  • ApplicationListener: 感知全階段:基於事件機制,感知事件。 一旦到了哪個階段可以做別的事

    • @Bean@EventListener事件驅動
    • SpringApplication.addListeners(…)SpringApplicationBuilder.listeners(…)
    • META-INF/spring.factories
  • SpringApplicationRunListener: 感知全階段生命周期 + 各種階段都能自定義操作; 功能更完善。

    • META-INF/spring.factories
  • ApplicationRunner: 感知特定階段:感知應用就緒Ready。卡死應用,就不會就緒

    • @Bean
  • CommandLineRunner: 感知特定階段:感知應用就緒Ready。卡死應用,就不會就緒

    • @Bean

最佳實戰:

  • 如果項目啟動前做事: BootstrapRegistryInitializerApplicationContextInitializer
  • 如果想要在項目啟動完成後做事:**ApplicationRunner** **CommandLineRunner**
  • 如果要干涉生命周期做事:**SpringApplicationRunListener**
  • 如果想要用事件機制:**ApplicationListener**

2. 完整觸發流程

9大事件觸發順序&時機

  1. ApplicationStartingEvent:應用啟動但未做任何事情, 除過註冊listeners and initializers.
  2. ApplicationEnvironmentPreparedEvent: Environment 準備好,但context 未創建.
  3. ApplicationContextInitializedEvent: ApplicationContext 準備好,ApplicationContextInitializers 調用,但是任何bean未載入
  4. ApplicationPreparedEvent: 容器刷新之前,bean定義信息載入
  5. ApplicationStartedEvent: 容器刷新完成, runner未調用

=以下就開始插入了探針機制====

  1. AvailabilityChangeEventLivenessState.CORRECT應用存活; 存活探針
  2. ApplicationReadyEvent: 任何runner被調用
  3. AvailabilityChangeEventReadinessState.ACCEPTING_TRAFFIC就緒探針,可以接請求
  4. ApplicationFailedEvent :啟動出錯

生命周期

應用事件發送順序如下:

輸入圖片說明

感知應用是否存活了:可能植物狀態,雖然活著但是不能處理請求。

應用是否就緒了:能響應請求,說明確實活的比較好。

3. SpringBoot 事件驅動開發

應用啟動過程生命周期事件感知(9大事件)應用運行中事件感知(無數種)

  • 事件發佈ApplicationEventPublisherAware註入:ApplicationEventMulticaster
  • 事件監聽組件 + @EventListener

輸入圖片說明

輸入圖片說明

事件發佈者

@Service
public class EventPublisher implements ApplicationEventPublisherAware {

    /**
     * 底層發送事件用的組件,SpringBoot會通過ApplicationEventPublisherAware介面自動註入給我們
     * 事件是廣播出去的。所有監聽這個事件的監聽器都可以收到
     */
    ApplicationEventPublisher applicationEventPublisher;

    /**
     * 所有事件都可以發
     * @param event
     */
    public void sendEvent(ApplicationEvent event) {
        //調用底層API發送事件
        applicationEventPublisher.publishEvent(event);
    }

    /**
     * 會被自動調用,把真正發事件的底層組組件給我們註入進來
     * @param applicationEventPublisher event publisher to be used by this object
     */
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}

事件訂閱者

@Service
public class CouponService {

    @Order(1)
    @EventListener
    public void onEvent(LoginSuccessEvent loginSuccessEvent){
        System.out.println("===== CouponService ====感知到事件"+loginSuccessEvent);
        UserEntity source = (UserEntity) loginSuccessEvent.getSource();
        sendCoupon(source.getUsername());
    }

    public void sendCoupon(String username){
        System.out.println(username + " 隨機得到了一張優惠券");
    }
}

3. 自動配置原理

1. 入門理解

應用關註的三大核心場景配置組件

1. 自動配置流程

輸入圖片說明

  1. 導入starter

  2. 依賴導入autoconfigure

  3. 尋找類路徑下 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件

  4. 啟動,載入所有 自動配置類 xxxAutoConfiguration

    1. 給容器中配置功能組件
    2. 組件參數綁定到 屬性類中。xxxProperties
    3. 屬性類配置文件首碼項綁定
    4. @Contional派生的條件註解進行判斷是否組件生效
  5. 效果:

    1. 修改配置文件,修改底層參數
    2. 所有場景自動配置好直接使用
    3. 可以註入SpringBoot配置好的組件隨時使用

2. SPI機制

  • Java中的SPI(Service Provider Interface)是一種軟體設計模式,用於 在應用程式中動態地發現和載入組件。 SPI的思想 是,定義一個介面或抽象類,然後通過在classpath中定義實現該介面的類來實現對組件的動態發現和載入。
  • SPI的主要目的是解決在應用程式中使用可插拔組件的問題。例如,一個應用程式可能需要使用不同的日誌框架或資料庫連接池,但是這些組件的選擇可能取決於運行時的條件。通過使用SPI,應用程式可以在運行時發現並載入適當的組件,而無需在代碼中硬編碼這些組件的實現類。
  • 在Java中,SPI的實現方式是通過在META-INF/services目錄下創建一個以服務介面全限定名為名字的文件,文件中包含實現該服務介面的類的全限定名。當應用程式啟動時,Java的SPI機制會自動掃描classpath中的這些文件,並根據文件中指定的類名來載入實現類。
  • 通過使用SPI,應用程式可以實現更靈活、可擴展的架構,同時也可以避免硬編碼依賴關係和增加代碼的可維護性。

以上回答來自ChatGPT-3.5

在SpringBoot中,META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

作業:寫一段java的spi機制代碼

3.功能開關

  • 自動配置:全部都配置好,什麼都不用管。 自動批量導入

    • 項目一啟動,spi文件中指定的所有都載入。
  • @EnableXxxx:手動控制哪些功能的開啟; 手動導入。

    • 開啟xxx功能
    • 都是利用 @Import 把此功能要用的組件導入進去

2. 進階理解

1. @SpringBootApplication

@SpringBootConfiguration

就是: @Configuration ,容器中的組件,配置類。spring ioc啟動就會載入創建這個類對象

@EnableAutoConfiguration:開啟自動配置

開啟自動配置

@AutoConfigurationPackage:掃描主程式包:載入自己的組件
  • 利用 @Import(AutoConfigurationPackages.Registrar.class) 想要給容器中導入組件。
  • 把主程式所在的的所有組件導入進來。
  • 為什麼SpringBoot預設只掃描主程式所在的包及其子包
@Import(AutoConfigurationImportSelector.class):載入所有自動配置類:載入starter導入的組件
List<String> configurations = ImportCandidates.load(AutoConfiguration.class, 	    getBeanClassLoader())
			.getCandidates();

掃描SPI文件:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@ComponentScan

組件掃描:排除一些組件(哪些不要)

排除前面已經掃描進來的配置類、和自動配置類

@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

2. 完整啟動載入流程

輸入圖片說明

生命周期啟動載入流程

3. 自定義starter

場景:抽取聊天機器人場景,它可以打招呼

效果:任何項目導入此starter都具有打招呼功能,並且問候語中的人名需要可以在配置文件中修改

  • 1.創建自定義starter項目,引入spring-boot-starter基礎依賴
  • 2.編寫模塊功能,引入模塊所有需要的依賴。
  • 3.編寫xxxAutoConfiguration自動配置類,幫其他項目導入這個模塊需要的所有組件
  • 4.編寫配置文件META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports指定啟動需要載入的自動配置
  • 5.其他項目引入即可使用

1. 業務代碼

自定義配置有提示。導入以下依賴重啟項目,再寫配置文件就有提示

@ConfigurationProperties(prefix = "robot")  //此屬性類和配置文件指定首碼綁定
@Component
@Data
public class RobotProperties {

    private String name;
    private String age;
    private String email;
}
@ConfigurationProperties(prefix = "robot")  //此屬性類和配置文件指定首碼綁定
@Component
@Data
public class RobotProperties {

    private String name;
    private String age;
    private String email;
}
<!--        導入配置處理器,配置文件自定義的properties配置都會有提示-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency><!--        導入配置處理器,配置文件自定義的properties配置都會有提示-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

2. 基本抽取

  • 創建starter項目,把公共代碼需要的所有依賴導入

  • 把公共代碼複製進來

  • 自己寫一個 RobotAutoConfiguration,給容器中導入這個場景需要的所有組件

    • 為什麼這些組件預設不會掃描進去?
    • starter所在的包和 引入它的項目的主程式所在的包不是父子層級
  • 別人引用這個starter,直接導入這個 RobotAutoConfiguration,就能把這個場景的組件導入進來

  • 功能生效。

  • 測試編寫配置文件

3. 使用@EnableXxx機制

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(RobotAutoConfiguration.class)
public @interface EnableRobot {


}@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(RobotAutoConfiguration.class)
public @interface EnableRobot {


}

別人引入starter需要使用 @EnableRobot開啟功能

4. 完全自動配置

  • 依賴SpringBoot的SPI機制
  • META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中編寫好我們自動配置類的全類名即可
  • 項目啟動,自動載入我們的自動配置類
你的壓力來源於無法自律,只是假裝努力,現狀跟不上內心欲望,所以你焦慮又恐慌。——楊不易
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 本文的起因是有在代碼倉庫發包後,同事問我“為什麼package.json 里的版本還是原來的,有沒有更新?”,這個時候我意識到,我們完全沒有必要在每次發佈的時候還特意去關註這個倉庫的版本號,只要在發佈打tag的時候同步一下即可,於是有了本 ...
  • ![你真的瞭解bind嗎](https://guizimo.oss-cn-shanghai.aliyuncs.com/img/%E4%BD%A0%E7%9C%9F%E7%9A%84%E4%BA%86%E8%A7%A3bind%E5%90%97.png) # 引言 ## 內容速遞 > 看了本文您能瞭解 ...
  • 對於各種類型的埋點來說,曝光埋點往往最為複雜、需要用到的技術也最全面、如果實現方式不合理可能造成的影響也最大,因此本文將重點介紹曝光埋點尤其是長列表(或滾動視圖)內元素曝光埋點的實現思路及避坑技巧 ...
  • # window.localStorage.setItem 和 localStorage.setItem 有什麼區別 - 在JavaScript中,localStorage.setItem和window.localStorage.setItem實際上是相同的, - 它們是對瀏覽器的本地存儲(Loca ...
  • 基於tauri+vite4+pinia2跨端後臺管理系統應用實例TauriAdmin。 tauri-admin 基於最新跨端技術 Tauri Rust webview2 整合 Vite4 構建桌面端通用後臺管理解決方案。搭載輕量級ve-plus組件庫、支持多視窗切換管理、vue-i18n多語言包、動 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 最近剛剛學習了Echarts的使用,於是想做一個小案例來鞏固一下。項目效果如下圖所示: 話不多說,開始進入實戰。 創建項目 這裡我們使用vue-cli來創建腳手架: vue create app 這裡的app是你要創建的項目的名稱, ...
  • 推薦使用壓縮軟體和殺毒軟體 7 - zip 使用火絨 # 一、基本數據類型與變數(上) ### 2.1 註釋 優點: 1. 代碼說明 沒註釋的代碼 有註釋的代碼 1. 不讓解釋器執行註釋的那句話 ### 2.2 單行註釋 單行註釋快捷鍵:ctrl + ? ### 2.3多行註釋 """""" (三個 ...
  • 先上java代碼: 先上java代碼: import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.*; import java.util.Sc ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...