用了這麼多年的 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
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...