SpringBoot3核心原理

SpringBoot3核心原理

事件和監聽器

生命周期監聽

場景:監聽應用的生命周期

可以通過下面步驟自定義SpringApplicationRunListener來監聽事件。
①、編寫SpringApplicationRunListener實現類
②、在META-INF/spring.factories中配置org.springframework.boot.SpringApplicationRunListener=自己的Listener,還可以指定一個有參構造器,接收兩個參數SpringApplication application, String[] args
③、springboot在spring-boot.jar中配置了默認的Listener,如下:
org.springframework.boot.SpringApplicationRunListener=
org.springframework.boot.context.event.EventPublishingRunListener
監聽器.png

場景實現
創建監聽器

MyApplicationListener

package com.louis.listener;import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;import java.time.Duration;/*** springboot應用生命周期監聽* @author XRY* @date 2023年07月14日14:51*/
public class MyApplicationListener implements SpringApplicationRunListener {@Overridepublic void starting(ConfigurableBootstrapContext bootstrapContext) {System.out.println("===========starting==========正在啟動=======");}@Overridepublic void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {System.out.println("===========environmentPrepared==========環境準備完成=======");}@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {//相當與IOC容器System.out.println("===========contextPrepared==========ioc容器準備完成=======");}@Overridepublic void contextLoaded(ConfigurableApplicationContext context) {System.out.println("===========contextLoaded==========ioc容器加載完成=======");}@Overridepublic void started(ConfigurableApplicationContext context, Duration timeTaken) {System.out.println("===========started==========啟動完成=======");}@Overridepublic void ready(ConfigurableApplicationContext context, Duration timeTaken) {System.out.println("===========ready==========準備就緒=======");}@Overridepublic void failed(ConfigurableApplicationContext context, Throwable exception) {System.out.println("===========failed==========應用啟動失敗=======");}
}

提示:

想要讓配置的監聽器生效,需要在根目錄下創建一個META-INF文件夾并添加文件spring.factories(它是一個key,value寫法:key為接口全類名, value為我們創建類的全類名)

org.springframework.boot.SpringApplicationRunListener=com.louis.listener.MyApplicationListener
springboot應用生命周期監聽

Listener先要從BootStrapContext引導整個項目啟動,主要分為下面的幾個步驟:

  1. 引導:利用BootstrapContext引導整個項目啟動

    starting:應用開始,調用SpringApplication的run方法,只要有了BootStrapContext就執行
    environmentPrepared:環境準備好(把啟動參數等綁定到環境變量中),但是ioc容器還沒有創建。(調一次)
    
  2. 啟動:

    contextPrepared: ioc容器創建并準備好,但是sources(主配置類)沒加載,并關閉上下文,組件還沒有創建(調一次)
    contextLoaded: ioc容器加載。著配置類加載進去,但是ioc容器還沒有刷新。(Bean都沒創建)
    started: ioc容器刷新了(容器中加入了Bean),但是runner沒調用。
    ready: ioc容器刷新了(容器中加入了Bean),所有runner調用完。

  3. 運行

    以前的步驟都正確執行,代表容器running
    生命周期全流程.png

事件觸發時機

1、各種回調監聽器介紹
監聽器監聽階段作用使用場景
BootstrapRegistryInitializer感知特定階段感知引導初始化META-INF/spring.factories
創建引導上下文bootstrapContext的時候觸發可以在主程序調用:application.add.BootstrapRegistryInitializer()
進行密鑰校對授權
ApplicationContextInitializer感知特定階段感知ioc容器初始化META-INF/spring.factories
ApplicationListener感知全階段基于事件機制,感知事件。@Bean或EventListener、SpringApplication.addListeners(…)或SpringApplicationBuilder.listeners(…)、META-INF/spring.factories
SpringApplicationRunListener感知全階段生命周期+各種階段自定義操作META-INF/spring.factories
ApplicationRunner感知特定階段感知應用就緒Ready的@Bean
CommandLineRunner感知特定階段感知應用就緒Ready的@Bean

總結:

如果項目啟動前做事:BootstrapRegistryInitializer和ApplicationContextInitializer
如果想要在項目啟動完成后做事:ApplicationRunner和CommandLineRunner
如果想要干涉生命周期:SpringApplicationRunListener
如果想要用事件機制:ApplicationListener

2、事件完整觸發流程(9種事件)
  • ApplicationStartingEvent:應用啟動但未做任何事情,
  • ApplicationEnvironmentPreparedEvent:Environment準備好,但context未創建
  • ApplicationContextInitializedEvent:ApplicationContext準備好,ApplicationContextInitializers調用,到那時任何bean未加載
  • ApplicationPreparedEvent:容器刷新之前,bean定義信息加載
  • ApplicationStartedEvent:容器刷新完成,runner未調用
  • AvailabilityChangeEvent:LivenessState.CORRECT應用存活,存活探針
  • ApplicationReadyEvent:任何runner被調用
  • AvailabilityChangeEvent:ReadinessState.ACCEPTING_TRAFFIC應用就緒,可以接收請求,就緒探針
  • ApplicationFailedEvent:啟動出錯

事件發送順序

事件發送順序.png
**兩個探針的作用是感知應用是否存貨和就緒。 **

3、SpringBoot事件驅動開發

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

  • 事件發布:ApplicationEventPublisherAware或注入:ApplicationEventMulticaser
  • 事件監聽:組件 + @EventListener
示例

事件驅動開發.png

創建service

AccountService

@Service
public class AccountService {public void addAccountScore(String username){System.out.println(username + "加了1分");}
}

CouponService

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

SystemService

@Service
public class SystemService {public void recordLog(String username, String password){System.out.println(username + "  ,密碼為" + password + "登錄信息已被記錄");}
}
不使用事件

LoginController

@RestController
public class LoginController {@AutowiredAccountService accountService;@AutowiredCouponService couponService;@AutowiredSystemService systemService;@GetMapping("login")public String login(@RequestParam String username,@RequestParam String password){//業務處理登錄System.out.println("業務處理登錄完成.........");//1、賬戶服務自動簽到加積分accountService.addAccountScore(username);//2、優惠服務隨機發放優惠券couponService.sendCoupon(username);//3、系統服務登記用戶登錄信息systemService.recordLog(username, password);return username + "登錄成功";}
}

測試事件開發.png
測試事件開發01.png

使用事件機制

創建實體類UserEntity

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {private String username;private String password;
}

創建事件LoginSuccessEvent,繼承ApplicationEvent

package com.louis.event;import com.louis.entity.UserEntity;
import org.springframework.context.ApplicationEvent;import java.awt.desktop.AppEvent;/*** @author XRY   登錄成功事件, 所有事件都推薦繼承ApplicationEvent* @date 2023年07月14日19:19*///登錄成功事件
public class LoginSuccessEvent extends ApplicationEvent {/*** @param source 代表誰登錄成功了*/public LoginSuccessEvent(UserEntity source) {super(source);}
}

創建事件發送類 EventPublisher

package com.louis.event;import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;/*** @author XRY* @date 2023年07月14日19:18*/
@Service
public class EventPublisher implements ApplicationEventPublisherAware {/*** 底層發送事件的組件,SpringBoot會通過ApplicationEventPublisherAware接口自動注入給我們*/ApplicationEventPublisher applicationEventPublisher;/*** 所有事件都可以發* @param event*/public void sendEvent(ApplicationEvent event){//用底層API發送事件applicationEventPublisher.publishEvent(event);}/*** 會被自動調用,把真正發事件的底層組件注入進來* @param applicationEventPublisher*/@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}
}

控制器LoginController

@RestController
public class LoginController {//事件@AutowiredEventPublisher eventPublisher;@GetMapping("login")public String login(@RequestParam String username,@RequestParam String password){//業務處理登錄System.out.println("業務處理登錄完成.........");//發送事件//1、創建事件信息LoginSuccessEvent event = new LoginSuccessEvent(new UserEntity(username, password));//2、發送事件eventPublisher.sendEvent(event);return username + "登錄成功";}
}

事件機制01.png
事件機制02.png

自動配置原理

入門理解

應用關注的三大核心:場景、配置、組件

1、 自動配置流程

自動配置流程.png

①、導入starter
②、依賴導入autoconfigure
③、尋找類路徑下META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.import文件
④、啟動,加載所有自動配置類-xxxAutoConfiguration
i、給容器種配置功能組件
ii、組件參數綁定到屬性類中。xxxProperties
iii、屬性類和配置文件前綴項綁定
iV、@Conditional派生的條件注解進行判斷是否組件生效
⑤、效果:
i、修改配置文件、修改底層參數
ii、所有場景自動配置好直接使用
iii、可以注入SpringBoot配置好的組件隨時使用。

2、SPI機制

SPI 全稱是 Service Provider Interface,是一種 JDK 內置的動態加載實現擴展點的機制,通過 SPI 技術我們可以動態獲取接口的實現類,不用自己來創建。這個不是什么特別的技術,只是 一種設計理念。它實際上是基于接口的編程+策略模式+配置文件組合實現的動態加載機制。

image.png
系統設計的各個抽象,往往有很多不同的實現方案,在面向對象的設計里,一般推薦模塊之間基于接口編程,模塊之間不對實現類進行硬編碼。一旦代碼里涉及具體的實現類,就違反了可拔插的原則,如果需要替換一種實現,就需要修改代碼。為了實現在模塊裝配的時候能不在程序里動態指明,這就需要一種服務發現機制。Java SPI就是提供這樣的一個機制:為某個接口尋找服務實現的機制。有點類似IOC的思想,就是將裝配的控制權移到程序之外,在模塊化設計中這個機制尤其重要。所以SPI的核心思想就是解耦。

3、功能開關
  • 自動配置:全部都配置好,什么都不用管,自動批量導入。

    項目啟動,spi文件中指定的所有都加載

  • @Enablexxx:手動控制哪些功能的開啟,手動導入。

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

進階理解

@SpringBootApplication是以下三個注解的復合注解:
①、@SpringBootConfiguration:就是@Configuration,容器中的組件,配置類。Spring ioc啟動就會加載創建這個類對象。
②、@EnableAutoConfiguration:開啟自動配置,由如下兩注解復合:

  • @AutoConfigurationPackage

掃描主程序包。利用@Import(AutoConfigurationPackages.Registrar.class)加載自己想要給容器中導入的組件。把主程序所在包的所有組件導入進來。即只掃描主程序及主程序所在的包及其子包。

  • @Import(AutoConfigurationImportSelector.class)

加載所有自動配置類,加載starter導入組件List configurations = ImportCandidates.load(AutoConfiguration.class,getBeanClassLoader()).getCandidates();
掃描SPI文件:“META-INF/spring/org.springframework.boot.autoconfigure.Autoconfiguration.imports”
③、@ComponentScan
組件掃描,排除一些組件,排除前面已經掃描進來的配置類和自動配置類。

自定義starter

場景:抽取聊天機器人場景,它可以打招呼。
效果:任何項目導入此starter都具有打招呼功能,并且問候語中的人名需要可以在配置文件中修改。

實現步驟

①、創建自定義starter項目,引入spring-boot-starter基礎依賴
②、編寫模塊功能,引入模塊所有需要的依賴,編寫xxxAutoConfiguration自動配置類
③、編寫配置文件META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports指定啟動需要加載的自動配置。
④、其他下項目引入即可使用。

通用業務代碼

小技巧:可以導入如下依賴重啟項目,再寫配置文件會有提示。

<!--導入配置處理器,自定義的properties配置文件會有提示-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency>
配置類
@ConfigurationProperties(prefix = "robot")
@Component
@Data
public class RobotProperties {private String name;private String email;private Integer age;
}

配置文件

robot.name=張三
robot.age=23
robot.email=louis@qq.com

通用功能

@Service
public class RobotService {@AutowiredRobotProperties robotProperties;public String sayHello(){return "你好:" + robotProperties.getName() + "   ;年齡:" + robotProperties.getAge();}
}

控制器

@RestController
public class RobotController {@AutowiredRobotService robotService;@GetMapping("/robot/hello")public String sayHello(){return robotService.sayHello();}
}

代碼.png

基本抽取(新建模塊)

新建模塊時不需要選擇任何場景。

復制公共功能

抽取.png

根據公共功能,添加場景

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
<!--導入配置處理器,自定義的properties配置文件會有提示-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency>

刪除主類

刪除主類.png

在需要引用項目下導入該starter

<!--自定義的starter-->
<dependency><groupId>com.louis</groupId><artifactId>boot3-robot-starter</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

在starter下編寫配置類

原因:SpringBoot項目只能掃描主程序以及主程序所在的子包,當導入自定義的starter時,不屬于這一層級。

@Configuration
@Import({RobotController.class, RobotService.class, RobotProperties.class})
public class RobotAutoConfiguration {}

在主程序導入配置類

boot3-07.png

@SpringBootApplication
@Import(RobotAutoConfiguration.class)
public class Boot307Application {public static void main(String[] args) {SpringApplication.run(Boot307Application.class, args);}}

引入starter不會讀取starter本身的配置。

編寫application.properties

robot.name=louie
robot.age=23
robot.email=louis@qq.com

測試

基本抽取.png
總結:

a、創建starter,將公共代碼所需的所有依賴導入
b、將公共代碼復制到starter
c、自己寫一個RobotAutoConfiguration,該容器中導入需要組件(主程序掃描規則)
d、測試功能

使用Enable機制

原因:在導入starter的時候,使用者可能不知道需要導入哪些相關的文件。

在我們的starter編寫注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({RobotAutoConfiguration.class})
public @interface EnableRobot {
}在主程序中使用@EnableRobot注解
@SpringBootApplication
@EnableRobot
public class Boot307Application {public static void main(String[] args) {SpringApplication.run(Boot307Application.class, args);}}

測試

基本抽取.png
總結:

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

完全自動

依賴SpringBoot的SPI機制"META-INF/spring/org.springframework.boot.autoconfigure.Autoconfiguration.imports"在其中放置RobotAutoConfiguration配置類的全類名。如:com.louis.starter.robot.config.RobotAutoConfiguration
import文件.png只需要導入starter,不用加任何注解。

測試

import配置后.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/167991.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/167991.shtml
英文地址,請注明出處:http://en.pswp.cn/news/167991.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

上市公司-股權性質數據(國企、央企)2003-2022年

上市公司-股權性質數據&#xff08;國企、央企&#xff09;是一個針對上市公司的數據集&#xff0c;主要涵蓋了A股公司股權性質的詳細信息&#xff0c;區分了公司是否為民營企業、國企或央企。這份數據集提供了每家上市公司的股權結構背景&#xff0c;對投資者、市場分析師和經…

Shell循環:for(二)

一、通過用戶列表文件創建用戶 需求&#xff1a;通過用戶列表文件創建用戶 [rootlocalhost ~]# cat user.txt qian yoa huang演示&#xff1a; [rootlocalhost ~]# vim foruser.sh #編寫腳本 #!/bin/bash for i in cat user.txt do useradd $i if [ $? -eq 0 ] thenech…

2023年亞太杯數學建模C題新能源汽車成品文章(思路模型代碼成品)

一、翻譯 新能源汽車是指采用先進的技術原理、新技術和新結構&#xff0c;以非常規車用燃料&#xff08;非常規車用燃料是指汽油和柴油以外的燃料(非常規車用燃料是指汽油和柴油以外的燃料&#xff09;&#xff0c;并集成了汽車動力控制和驅動等先進技術的汽車。新能源汽車包括…

C++入門第九篇---Stack和Queue模擬實現,優先級隊列

前言&#xff1a; 我們已經掌握了string vector list三種最基本的數據容器模板&#xff0c;而對于數據結構的內容來說&#xff0c;其余的數據結構容器基本都是這三種容器的延申和擴展&#xff0c;在他們的基礎上擴展出更多功能和用法&#xff0c;今天我們便來模擬實現一下C庫中…

superset 后端增加注冊接口

好煩啊-- &#xff1a;< 1.先定義modes: superset\superset\models\user.py # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information…

Tars框架 Tars-Go 學習

Tars 框架安裝 網上安裝教程比較多&#xff0c;官方可以參數這個 TARS官方文檔 (tarsyun.com) 本文主要介紹部署應用。 安裝完成后Tars 界面 增加應用amc 部署申請 amc.GoTestServer.GoTestObj 名稱不知道的可以參考自己創建的app config 點擊刷新可以看到自己部署的應用 服…

獲取當日的日期三個月后的日期

使用 java.time.LocalDate 類進行計算 import java.time.LocalDate;public class ThreeMonthsLaterExample {public static void main(String[] args) {// 獲取當前日期LocalDate currentDate LocalDate.now();// 添加三個月LocalDate threeMonthsLater currentDate.plusMont…

【阿里云服務器】2023安裝寶塔面板8.0.4

文章目錄 前言安裝寶塔遠程鏈接服務器輸入安裝寶塔命令放行寶塔端口 一鍵安裝環境附錄重裝系統Linux系統卸載寶塔方式一方式二 遇見的問題 前言 鏡像是CentOS 7.9.4 安裝寶塔 遠程鏈接服務器 輸入安裝寶塔命令 yum install -y wget && wget -O install.sh https://…

Android 13.0 系統settings系統屬性控制一級菜單顯示隱藏

1.概述 在13.0的系統rom定制化開發中,系統settings的一級菜單有些在客戶需求中需要去掉不顯示,所以就需要通過系統屬性來控制顯示隱藏, 從而達到控制一級菜單的顯示的目的,而系統settings是通過靜態加載的方式負責顯示隱藏,接下來就來實現隱藏顯示一級菜單的 功能實現 2.…

2023年亞太杯數學建模A題水果采摘機器人的圖像識別功能(基于yolov5的蘋果分割)

注&#xff1a;.題中附錄并沒有給出蘋果的標簽集&#xff0c;所以需要我們自己通過前4問得到訓練的標簽集&#xff0c;采用的是yolov5 7.0 版本&#xff0c;該版本帶分割功能 一&#xff1a;關于數據集的制作&#xff1a; clc; close all; clear; %-----這個是生成yolov5 數據…

任務4-繪制圖形

python字典的使用方法 !echo $(date)‘開始下載并解壓’ && curl -o Task4.zip https://zyenv-1302342904.cos.ap-guangzhou.myqcloud.com/datas/TianJin/Task4_TJ_ZZ.zip && unzip -o Task4.zip > /dev/null 2>&1 && echo $(date)‘解壓完…

學習課題:逐步構建開發播放器【QT5 + FFmpeg6 + SDL2】

目錄 一、播放器開發(一)&#xff1a;播放器組成大致結構與代碼流程設計 二、播放器開發(二)&#xff1a;了解FFmpeg與SDL常用對象和函數 三、播放器開發(三)&#xff1a;FFmpeg與SDL環境配置 四、播放器開發(四)&#xff1a;多線程解復用與解碼模塊實現 五、播放器開發(五…

Linux應用開發基礎知識——I2C應用編程(十三)

一、無需編寫驅動程序即可訪問 I2C 設備 APP 訪問硬件肯定是需要驅動程序的&#xff0c;對于 I2C 設備&#xff0c;內核提供了驅動程序 drivers/i2c/i2c-dev.c&#xff0c;通過它可以直接使用下面的 I2C 控制器驅動程序來訪問 I2C 設備。 i2c-tools 是一套好用的工具&#xff0…

虛擬機系列:Oracle VM VirtualBox虛擬機的使用教程和使用體驗情況反饋

Oracle VM VirtualBox虛擬機的使用教程和使用體驗情況反饋 一. 簡述:二. 下載三. 安裝解壓后選擇需要的版本點擊安裝1:第一步,點擊安裝,點擊下一步2. 這里直接點擊下一步,3. 網絡警告選擇:是4. 準備好以后,點擊安裝5. 點擊完成即可四. 打開五. 創建虛擬機1. 輸入虛擬機名…

H5(uniapp)中使用echarts

1,安裝echarts npm install echarts 2&#xff0c;具體頁面 <template><view class"container notice-list"><view><view class"aa" id"main" style"width: 500px; height: 400px;"></view></v…

MySQL 中的 JSON_CONTAINS 函數詳解

在處理 MySQL 中的 JSON 數據時&#xff0c;我們經常需要檢查一個 JSON 文檔是否包含特定的值。這時&#xff0c;JSON_CONTAINS 函數就顯得非常有用。 JSON_CONTAINS函數介紹 JSON_CONTAINS 是 MySQL 提供的一個 JSON 函數&#xff0c;用于測試一個 JSON 文檔是否包含特定的值…

SQLite 和 SQLiteDatabase 的使用

實驗七&#xff1a;SQLite 和 SQLiteDatabase 的使用 7.1 實驗目的 本次實驗的目的是讓大家熟悉 Android 中對數據庫進行操作的相關的接口、類等。SQLiteDatabase 這個是在 android 中數據庫操作使用最頻繁的一個類。通過它可以實現數據庫的創建或打開、創建表、插入數據、刪…

22、什么是中間件和權限攔截中間件實操

新建中間件 middleware\auth.js // 定義權限判斷中間件&#xff0c;中間件的第一個參數是context export default ({store, redirect}) > {console.log("中間件被調用")// if (!store || !store.state.userinfo) {// redirect("/")// } }頁面使用…

CF -- Educational Codeforces Round 158 (Rated for Div. 2) -- D 補題記錄

Yet Another Monster Fight Problem - D - Codeforces 題目大意&#xff1a; 現在給你一堆怪物&#xff0c;你擁有法術&#xff08;一個法術可以連續攻擊這n個所有怪物&#xff09;&#xff0c;你可以選擇任意一個怪物作為法術的第一個攻擊目標&#xff08;傷害為x&#xff…

【MySQL】索引與事務

&#x1f451;專欄內容&#xff1a;MySQL?個人主頁&#xff1a;子夜的星的主頁&#x1f495;座右銘&#xff1a;前路未遠&#xff0c;步履不停 目錄 一、索引1、使用場景2、使用索引創建索引查看索引刪除索引 3、底層數據結構&#xff08;非常重要&#xff09; 二、事務1、概念…