用了這麼多年的 SpringBoot 你知道什麼是 SpringBoot 的 Web 類型推斷嗎?

来源:https://www.cnblogs.com/zi-you/archive/2022/12/26/17006734.html
-Advertisement-
Play Games

用了這麼多年的 SpringBoot 那麼你知道什麼是 SpringBoot 的 web 類型推斷嗎? 估計很多小伙伴都不知道,畢竟平時開發做項目的時候做的都是普通的 web 項目並不需要什麼特別的瞭解,不過抱著學習的心態,阿粉今天帶大家看一下什麼是 SpringBoot 的 web 類型推斷。 S ...


用了這麼多年的 SpringBoot 那麼你知道什麼是 SpringBootweb 類型推斷嗎?

估計很多小伙伴都不知道,畢竟平時開發做項目的時候做的都是普通的 web 項目並不需要什麼特別的瞭解,不過抱著學習的心態,阿粉今天帶大家看一下什麼是 SpringBootweb 類型推斷。

SpringBoot 的 web 類型有哪些

既然是web 類型推斷,那我們肯定要知道 SpringBoot 支持哪些類型,然後才能分析是怎樣進行類型推斷的。

根據官方的介紹 SpringBootweb 類型有三種,分別是,NONESERVLETREACTIVE,定義在枚舉 WebApplicationType 中,這三種類型分別代表了三種含義:

  1. NONE:不是一個 web 應用,不需要啟動內置的 web 伺服器;
  2. SERVLET:基於 servletweb 應用,需要啟動一個內置的 servlet 伺服器;
  3. REACTIVE:一個 reactiveweb 應用,需要啟動一個內置的 reactive 伺服器;
public enum WebApplicationType {
	NONE,
	SERVLET,
	REACTIVE;
}

web 類型推斷

上面提到了 SpringBoot 的三種 web 類型,接下來我們先通過代碼驗證一下,然後再分析一下 SpringBoot 是如何進行類型推斷的。

首先我們通過在 https://start.spring.io/ 快速的構建三種類型的項目,三種類型的項目配置除了依賴不一樣之外,其他都一樣,如下所示

None web

none

下載後的項目文件 pom 中對應的依賴為

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
</dependency>

Servlet web

servlet

下載後的項目文件 pom 中對應的依賴為

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Reactive web

reactive

下載後的項目文件 pom 中對應的依賴為

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

接下來我們依次啟動三個項目看看有什麼區別,

啟動 None web

none-web

通過啟動日誌我們可以看到,在 None web 類型下,應用啟動運行後就自動關閉了,並沒有啟動內置的 web 伺服器,也沒有監聽任何埠。接下來我們看看其他兩種類型 web 的啟動日誌都是怎麼樣的。

啟動 Servlet web

servelt-web

通過啟動日誌我們可以看到這裡啟動了內置的 Tomcat Servlet 伺服器,監聽了 8080 埠,應用程式並不會像 None 類型一樣,啟動後就自動關閉。

啟動 Reactive web

reactive-web

通過啟動日誌我們可以看到,這裡啟動了內置的 Netty 伺服器,並監聽在 8080 埠上(如果啟動失敗記得把上面 servlet web 關閉,不然埠會衝突)。

三種類型的服務我們都成功啟動了,那麼接下來的問題就是 SpringBoot 是如何判斷出該使用哪種類型的呢?

這三個服務我們只有依賴不一樣,很明顯肯定和依賴有關係,接下來我們就來研究一下 SpringBoot 是如何實現的。

SpringBoot Web 類型推斷原理

我們在 main 方法中點擊 run 方法,

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
}

在構造函數中我們可以看到其中有這麼一行 this.webApplicationType = WebApplicationType.deduceFromClasspath();根據屬性名稱我們可以推斷,web 類型就是根據 WebApplicationType.deduceFromClasspath(); 這個靜態方法來判斷的。接下來我們看下這個方法的細節。

如上圖所示,可以看到 SpringBoot 底層是通過 ClassUtils.isPresent() 方法來判斷對應的 web 類型類是否存在來判斷 web 類型的。

在前類路徑下麵如果當 org.springframework.web.reactive.DispatcherHandler 存在而且 org.springframework.web.servlet.DispatcherServletorg.glassfish.jersey.servlet.ServletContainer 都不存在的時候說明當前應用 web 類型為 Reactive

javax.servlet.Servletorg.springframework.web.context.ConfigurableWebApplicationContext 任何一個不存在的時候,就說明當前應用是 None 類型非 web 應用。否則當前應用就為 Servlet 類型。

而我們再看這個 ClassUtils.isPresent() 方法,可以發現底層是通過 className 在類路徑上載入對應的類,如果存在則返回 true,如果不存在則返回 false
image-20221224154733977

因此這也解釋了為什麼我們在 pom 文件中只要加入對應的依賴就可以直接得到相應的 web 類型了,因為當我們在 pom 中加入相應的依賴過後,類路徑裡面就存在了前面判斷的對應的類,再通過 ClassUtils.isPresent() 就判斷出來當前應用屬於那種 web 類型了。

內置伺服器是如何創建的

知道了 SpringBoot 是如何進行 web 類型推斷的,那麼接下來一個問題就是 SpringBoot 是如何根據 web 類型進行相應內置 web 伺服器的啟動的呢?這裡我們以 Reactive web 為例進行調試追蹤。

首先我們在 SpringApplicationrun 方法 createApplicationContext() 下一行打斷點,可以發現創建成功的 context 類型為 AnnotationConfigReactiveWebServerApplicationContext 很明顯在這一步的時候就已經根據類型推斷得到了當前的應用 web 類型為 Reactive,並且根據 web 類型創建出了對應的 ApplicationContext

reactive-web

緊接著我們進入 org.springframework.boot.SpringApplication#refreshContext 方法,最後我們可以進入到 org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#refresh 方法中,因為 AnnotationConfigReactiveWebServerApplicationContext 繼承了 ReactiveWebServerApplicationContext

繼續通過引用關係,我們可以找到 org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext#onRefresh 方法,而在這個方法裡面我們就會發現瞭如下代碼,此處就會創建一個 webServer

具體創建的方法在 WebServerManager 裡面,跟著繼續往下找我們可以找到 createHttpServer() 方法,在 createHttpServer() 方法中就創建了 HttpServer 並且綁定了預設的埠 8080。具體過程,如下幾張接入所示,感興趣的可以自行跟蹤 debug,至此一個 Reactive 內置伺服器就創建成功了,同樣的 Servlet 伺服器也是類似的。




總結

Spring 的出現給 Java 程式員帶來了春天,而 SpringBoot 框架的出現又極大的加速了程式員的開發效率,然而很多時候我們在使用她的便利的同時會缺少對於底層系統實現的把握,希望這篇文章弄幫助大家對 SpringBoot 產生更多的理解。

本文來自博客園,作者:zi-you,轉載請註明原文鏈接:https://www.cnblogs.com/zi-you/p/17006734.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在 JavaScript 中,有時候你可能會發現 0.1+0.2 不等於 0.3。這是因為 JavaScript 使用的是浮點數來表示小數,而浮點數在電腦內部是用二進位表示的,這導致了一些精度問題。 ...
  • 在 JavaScript 中,巨集任務和微任務是指在執行代碼的過程中的兩種不同的任務類型。 巨集任務(macro task)指的是瀏覽器在執行代碼的過程中會調度的任務,比如事件迴圈中的每一次迭代、setTimeout 和 setInterval 等。巨集任務會在瀏覽器完成當前同步任務之後執行。 微任務(m... ...
  • 今天,收到一個很有意思的提問,如何實現類似如下的背景效果圖: 嗯?核心主體是由多個六邊形網格疊加形成。 那麼我們該如何實現它呢?使用純 CSS 能夠實現嗎? 當然可以,下麵我們就將嘗試如何使用 CSS 去實現這樣一個背景效果。 如何繪製六邊形? 首先,看到這樣一個圖形,如果想要使用一個標簽完成整個背 ...
  • 序 2020 年 10 月 17 日,我正式發佈了 Fantastic-admin 這款基於 Vue 的中後臺管理系統框架。在這兩年多的時間里,我陸續寫了幾篇我在開發這套框架中的一些心得和技術總結: 2020 年《我是如何設計後臺框架里那些錦上添花的動畫效果》 2020 年《一勞永逸,解決基於 ke ...
  • 1 String不可變性 String類被聲明為 final,因此它不可被繼承。 內部使用char數組存儲數據,該數組被聲明為final,這意味著value數組初始化之後就不能再指向其它數組。 String內部沒有改變value數組的方法 String類中所有修改String值的方法,如果內容沒有改 ...
  • ​ 一、前言 本篇文章內容為個人學習分享,讀代碼須知以下 樂理的基本知識,以及十二平均律(波的頻率與音高的標準),個人推薦在維基百科中搜索十二平均律表。 二、整體思想 在主函數中,將一些簡單的樂譜按照節拍,按鍵,基調,半音改變經行拆解。 然後我個人學習時,以440hz為標準的do依次類推,得到的基礎 ...
  • 家居網購項目實現08 以下皆為部分代碼,詳見 https://github.com/liyuelian/furniture_mall.git 19.功能18-添加家居到購物車 19.1需求分析/圖解 會員登錄後,可以添加家居到購物車 完成購物車的設計和實現 每添加一個家居,購物車的數量+1並顯示 1 ...
  • 怎麼用WordPress給自己搭建了一個網站?可能很多人都想擁有屬於自己的網站,這篇文章就找你怎麼利用WordPress搭建屬於自己的網站。如果你也正好有搭建個人網站的想法,那麼本文會給你一個參考,我儘量寫的比較詳細,給自己做一個記錄,也給大家一個參考。 寫在前面 在教程之前,先給大家show 一下 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...