位元組二面:為什麼SpringBoot的 jar 可以直接運行?我說因為內嵌了Tomcat容器,他讓我出門左轉。。

来源:https://www.cnblogs.com/coderacademy/p/18112038
-Advertisement-
Play Games

Spring Boot應用的jar包因其Fat JAR構建、自定義載入器、內嵌Web容器及自動配置特性,通過Maven或Gradle插件統一打包所有依賴,實現Main-Class指定的啟動器載入應用,簡化部署,實現跨平臺直接運行,大幅提升開發與運維效率。 ...


引言

在傳統的Java應用程式開發和部署場景中,開發者往往需要經歷一系列複雜的步驟才能將應用成功部署到生產環境。例如,對於基於Servlet規範的Java Web應用,開發完成後通常會被打包成WAR格式,然後部署到像Apache Tomcat、Jetty這樣的Web容器中。這一過程中,不僅要管理應用本身的編譯產物,還需要處理各種第三方依賴庫的版本和載入順序,同時在伺服器端進行相應的配置以確保應用正常運行。

隨著Spring Boot產生,它以其開箱即用、約定優於配置的理念徹底改變了Java應用的開發體驗。其中一個標誌性特征便是Spring Boot應用可以被打包成一個可直接運行的jar文件,無需外部容器的支持。

當提及“Spring Boot的jar可以直接運行”,我們不禁好奇:這背後究竟是怎樣的機制讓一個簡單的命令行操作就能啟動一個完整的Web服務或任何類型的Java應用呢?本文將深入剖析Spring Boot的打包過程和運行原理,揭示其jar包是如何巧妙地集成了依賴、嵌入了Web容器、實現了自動配置等功能,從而使得開發人員能夠迅速地將應用部署到任何支持Java的環境中。

springboot的jar包為什麼可以直接運行.png

SpringBoot JAR包基礎概念

Fat JAR(也稱作Uber JAR,也被戲稱為胖Jar)是一種特殊的Java歸檔(JAR)文件,它將應用程式所需的全部依賴庫與應用程式自身的類文件合併到了同一個JAR文件中。在Spring Boot上下文中,Fat JAR被用於構建一種完全自包含且可獨立運行的應用程式包。這樣的jar文件不僅僅包含項目的主代碼,還包括了所有必要的第三方庫、資源文件等一切運行時所需要的組件。

Fat JAR的核心特點是“自包含”,意味著只需分發這一個文件即可部署應用,無需再額外處理眾多的依賴庫。這種形式極大地方便了應用的快速部署與遷移,尤其適合於雲端部署或者無網路環境下的安裝。

而對於普通jar包來說,它通常僅包含一個模塊或應用程式的一部分,主要用來封裝和組織Java類及相關資源。在Java生態系統中,一個普通的jar包可能僅是一個庫,或者一組相關功能的集合,但它不會包含其他依賴的jar包,因此在運行時需要與之相關的其他庫一起存在於類路徑中。

相比之下,Fat JAR則解決了依賴管理的問題,通過將所有的依賴都納入其中,避免了由於類路徑設置不正確導致的“缺失類”或“找不到類”的問題。在Spring Boot項目中,通過Maven或Gradle插件可以輕易地構建出這樣的Fat JAR,使得最終生成的jar文件成為一個真正的“一站式”解決方案,只需使用java -jar命令就可以啟動整個應用程式,無需預先配置複雜的類路徑環境。

Spring Boot應用打包機制

Spring Boot應用打包機制充分利用了Maven或Gradle構建工具的強大功能,旨在簡化傳統Java應用的構建與部署流程。其核心在於創建一個可執行的Fat JAR,使得開發者能夠輕鬆地將整個Spring Boot應用及其依賴項打包成單個文件,從而實現一鍵啟動和便捷部署。

我們以Maven打包為例:

對於使用Maven構建的Spring Boot應用,spring-boot-maven-plugin是關鍵插件,負責處理Fat JAR的構建。在pom.xml文件中,通常會看到如下配置:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<version>${spring-boot.version}</version>
			<configuration>
				<!-- 可選配置項,如mainClass屬性指定入口類 -->
				<mainClass>${start-class}</mainClass>
			</configuration>
			<executions>
				<execution>
					<goals>
						<goal>repackage</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

通過mvn package命令,Maven首先會按照標準流程構建項目,隨後spring-boot-maven-plugin會執行repackage目標,該目標會重新包裝已生成的標準JAR文件,將其轉換為包含所有依賴項和適當的啟動器信息的Fat JAR。這樣生成的JAR可以直接通過java -jar命令啟動。

Spring Boot應用打包機制均確保了生成的包不僅包含了項目本身的類,還包含了運行時所必需的所有依賴庫,以及一些特定的元數據(如MANIFEST.MF中的啟動類信息)。這一特性大大簡化了部署過程,並有助於提升應用的可移植性和維護性。Fat jar中的內容:

image.png

  • META-INF/: 包含MANIFEST.MF文件和其他元數據信息,其中Main-Class屬性指向Spring Boot的啟動類載入器。
  • BOOT-INF/classes/: 存放項目自身的類文件和資源文件。
  • BOOT-INF/lib/: 放置所有依賴的jar包,包括Spring Boot starter依賴以及其他第三方庫。(如果項目中有靜態資源文件,也會在BOOT-INF下有對應的static、templates等目錄)

Spring Boot啟動器與Loader機制

Spring Boot應用的jar包可以直接運行主要依賴於它的啟動器以及Loader機制,而對於Loader機制主要利用MANIFEST.MF文件以及其內部類載入邏輯。

MANIFEST.MF文件是什麼?

MANIFEST.MFJAR文件內的一個標準元數據文件,它包含了關於JAR包的基本信息和運行指令。在Spring Boot應用的jar包中,MANIFEST.MF尤為重要,因為它設置了Main-Class屬性,指示了用於啟動整個應用程式的類,這個類通常是org.springframework.boot.loader.JarLauncher或其他由Spring Boot提供的啟動器類。

image.png

Main-Class屬性指向的JarLauncher類是Spring Boot自定義的類載入器體系的一部分。JarLauncher繼承自org.springframework.boot.loader.Launcher,專門用於啟動以Fat JAR形式發佈的Spring Boot應用。JarLauncher負責創建一個類載入器LaunchedURLClassLoader

image.png
image.png

當通過java -jar命令執行Spring Boot jar包時,JVM會依據MANIFEST.MF中的Main-Class啟動指定的啟動器。

JarLauncher獲取MainClass源碼.png

Spring Boot的啟動器類載入器LaunchedURLClassLoader首先會讀取MANIFEST.MF中的附加屬性,如Start-Class(標識應用的實際主類)和Spring-Boot-Lib(指向內部依賴庫的位置)。

image.png

image.png

啟動類載入器工作流程如下:

  1. 當啟動器類載入器啟動時,它會根據MANIFEST.MF中的信息來組織類路徑,保證所有內部的依賴庫都能正確地被載入。

  2. 載入器會區分出 BOOT-INF/classes中的應用程式類和 BOOT-INF/lib 下的依賴庫,分別處理並加入到類載入器的搜索路徑中。

  3. 載入器載入並執行實際的Start-Class,即應用的主類,觸發Spring Boot框架的初始化和應用的啟動流程。比如示例中的應用主類:com.springboot.base.SpringBootBaseApplication

Spring Boot的啟動器和載入器機制有效地實現了對自包含jar包的管理和執行,我們無需關心複雜的類路徑配置和依賴載入,只需通過一個簡單的命令即可啟動一個完整、獨立運行的應用程式。

內嵌Web容器

Spring Boot的一大特色就是能夠無縫整合併內嵌多種輕量級Web容器,比如:Apache TomcatJettyUndertow以及Reactor Netty(對於響應式編程模型)。內嵌Web容器的引入極大地簡化了Web應用的部署流程,我們不再需要在本地或伺服器上獨立安裝和配置Web伺服器(比如以前還要在本地安裝tomcat)。

當Spring Boot應用引入了spring-boot-starter-web依賴時,預設情況下會自動配置並啟動一個內嵌的Web容器。在Spring Boot啟動的過程中,內嵌容器作為應用的一部分被初始化並綁定到特定埠上,以便對外提供HTTP服務。

Spring Boot內嵌web容器的優點在於簡化部署,通過將Web容器內置於應用中,只需分發單一的JAR文件,就能在乾凈的環境中運行應用,避免了與現有Web伺服器版本衝突或配置不當等問題;同時加快了啟動速度,尤其在開發和測試階段,實現近乎即時的熱重啟;提高了應用的穩定性,因為開發環境和生產環境使用相同的Web容器,降低了因環境差異導致的問題;此外,雖然容器是內嵌的,但仍然可以進行全面的配置調整,如埠、連接數、SSL設置等,以滿足不同場景的需求。通過內嵌Web容器,Spring Boot真正實現了“開箱即用”的理念。

自動配置與類路徑掃描

Spring Boot的核心特性之一就是其強大的自動配置能力,它允許應用在幾乎零配置的情況下快速啟動並運行。

當應用啟動時,Spring Boot會讀取resource/META-INF/spring.factories文件,該文件列出了所有可用的自動配置類。當它檢測到應用環境中對應的自動配置類就會生效,通過@Configuration註解的類創建並註冊Bean到Spring容器中,從而實現Bean的自動裝配。

這裡說明下,在springboot3.x以後,就不在從resource/META-INF/spring.factories讀取自動配置類了,而是從org.springframework.boot.autoconfigure.AutoConfiguration.imports中讀取,這一點請參考文章:華為二面:SpringBoot如何自定義_Starter_?

並且Spring Boot還採用條件註解(如@ConditionalOnClass@ConditionalOnMissingBean等)來智能判斷何時應用特定的配置。這些註解可以根據類路徑中是否存在特定類、系統屬性或環境變數的值等因素,決定是否應該激活某個自動配置類。這意味著只有當滿足特定條件時,相應的Bean才會被創建和註入。

而對於應用主類則是用@SpringBootApplication註解標識。@SpringBootApplication是一個複合註解,包含了@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan三個註解的功能。其中

  • @SpringBootConfiguration是一個Spring配置類,可以替代@Configuration註解,聲明當前類是Spring配置類,裡面包含了一系列@Bean方法或@ConfigurationProperties等配置。
  • @EnableAutoConfiguration啟用自動配置特性,告訴Spring Boot根據應用類路徑中的依賴來自動配置Bean。Spring Boot會根據類路徑掃描的結果,智能地決定哪些自動配置類應當生效。
  • @ComponentScan會自動掃描和管理Spring組件,包括@Service、@Repository、@Controller和@Component等註解標註的類。通過該註解,Spring Boot能自動發現和管理應用中的各個組件,並將其註冊為Spring容器中的Bean。

通過上述機制,Spring Boot能夠智能識別項目依賴、自動配置Bean,並結合類路徑掃描確保所有相關的組件和服務都被正確地初始化和管理,我們就可以專註於業務邏輯的開發,而不必過多考慮基礎設施層面的配置問題。

總結

Spring Boot 應用程式被打包成的jar包之所以可以直接通過 java -jar 命令運行,是因為Spring Boot在構建過程中做了一些特殊的設計和配置。具體原因:

  1. Fat/Uber JAR: Spring Boot使用maven插件spring-boot-maven-plugin(或Gradle對應的插件)將項目及其所有依賴項打包成一個單一的、自包含的jar文件,通常稱為“Fat JAR”或“Uber JAR”。這意味著不僅包含了自己的類文件,還包含了運行應用所需的所有第三方庫。

  2. Manifest.MF: 在打包過程中,此插件會修改MANIFEST.MF文件,這是jar包中的一個元數據文件。在MANIFEST.MF中,特別指定了Main-Class屬性,該屬性指向Spring Boot的一個內置的啟動類(如org.springframework.boot.loader.JarLauncher),這個啟動器類知道如何正確啟動Spring Boot應用程式。

  3. 嵌入式Servlet容器:Spring Boot預設集成了諸如Tomcat、Jetty或Undertow等嵌入式Web容器,使得無需外部伺服器環境也能運行Web應用。

  4. 啟動器類載入器:當通過java -jar運行Spring Boot應用時,JVM會根據MANIFEST.MF中的Main-Class找到並運行指定的啟動器類。這個啟動器類載入器能夠解壓並載入內部的依賴庫,並定位到實際的應用主類(在spring-boot-starter-parent@SpringBootApplication註解標記的類),進而執行其main方法。

  5. 類路徑掃描和自動配置:Spring Boot應用通過特定的類路徑掃描機制和自動配置功能,能夠在啟動時識別出應用所依賴的服務和組件,並自動配置它們,大大簡化了傳統Java應用的配置和部署過程。

Spring Boot通過精心設計的打包流程和啟動器類,使得生成的jar包可以直接作為一個獨立的應用程式運行,極大地簡化了部署和運維複雜度。

本文已收錄於我的個人博客:碼農Academy的博客,專註分享Java技術乾貨,包括Java基礎、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中間件、架構設計、面試題、程式員攻略等


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

-Advertisement-
Play Games
更多相關文章
  • 本文首發於公眾號:Hunter後端 原文鏈接:Python面試必備一之迭代器、生成器、淺拷貝、深拷貝 這一篇筆記主要介紹 Python 面試過程中常被問到的一些問題,比如: Python 中的迭代器和生成器是什麼,有什麼作用 Python 中不可變類型有哪些 在 Python 函數中,傳遞參數傳遞的 ...
  • 拓展閱讀 常見免費開源繪圖工具 OmniGraffle 創建精確、美觀圖形的工具 UML-架構圖入門介紹 starUML UML 繪製工具 starUML 入門介紹 PlantUML 是繪製 uml 的一個開源項目 UML 等常見圖繪製工具 繪圖工具 draw.io / diagrams.net 免 ...
  • 本文介紹瞭如何配置更好的編碼平臺,因為 NOI 系列中的 Dev-C++ 用戶體驗不佳。需要能夠使用無高亮顯示的主要語法和功能強大的電腦。使用清華的國內鏡像安裝帶有 Clang 的 MSYS2,配置環境變數並安裝 VSCode。最後,通過安裝 Visual Studio Code 中文(簡體)語言... ...
  • Entity主要用於ORM(對象關係映射)框架中,如Hibernate、MyBatis等,以便將資料庫中的數據映射為對象,方便進行業務操作。 Entity通常與資料庫表一一對應,代表業務數據的基本單元。 通常放在項目的model或entity包下。 DAO(數據訪問對象):DAO是連接業務邏輯和數據 ...
  • ★ 基本定義 一種用起來像是使用的實例屬性一樣的特殊屬性,可以對應於某個方法 ★ property屬性的兩種方式 裝飾器 => 在方法上應用裝飾器 類屬性 => 在類中定義值為property對象的類屬性 ★ 裝飾器方式 代碼示例 class Goods(object): def __init__( ...
  • ​FFmpeg內置了aac音頻格式,在《FFmpeg開發實戰:從零基礎到短視頻上線》一書的“5.2.2 Linux環境集成mp3lame”又介紹瞭如何給FFmpeg集成mp3格式,常見的音頻文件除了這兩種之外,還有ogg和amr兩種格式也較常用。其中ogg格式的編解碼依賴於libogg和libvor ...
  • getpass模塊提供了兩個函數getpass和getuser,隱式密碼輸入和獲取當前用戶,當你想要用戶輸入密碼,基於安全考慮,密碼又不能明文顯示出來的時候就可以使用這個模塊。 getpass(prompt='Password: ', stream=None) 沒有回顯地獲取用戶輸入的密碼。 使用 ...
  • 0 prompt engineer 就是prompt工程師它的底層透視。 1 學習大模型的重要性 底層邏輯 人工智慧大潮已來,不加入就可能被淘汰。就好像現在職場里誰不會用PPT和excel一樣,基本上你見不到。你問任何一個人問他會不會用PPT,他都會說會用,只是說好還是不好。你除非說這個崗位跟電腦完 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...