在傳統的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的環境中。
圖片
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應用打包機制充分利用了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中的內容:
圖片
Spring Boot應用的jar包可以直接運行主要依賴于它的啟動器以及Loader機制,而對于Loader機制主要利用MANIFEST.MF文件以及其內部類加載邏輯。
MANIFEST.MF是JAR文件內的一個標準元數據文件,它包含了關于JAR包的基本信息和運行指令。在Spring Boot應用的jar包中,MANIFEST.MF尤為重要,因為它設置了Main-Class屬性,指示了用于啟動整個應用程序的類,這個類通常是org.springframework.boot.loader.JarLauncher或其他由Spring Boot提供的啟動器類。
圖片
Main-Class屬性指向的JarLauncher類是Spring Boot自定義的類加載器體系的一部分。JarLauncher繼承自org.springframework.boot.loader.Launcher,專門用于啟動以Fat JAR形式發布的Spring Boot應用。JarLauncher負責創建一個類加載器LaunchedURLClassLoader。
圖片
圖片
當通過java -jar命令執行Spring Boot jar包時,JVM會依據MANIFEST.MF中的Main-Class啟動指定的啟動器。
JarLauncher獲取MainClass源碼
Spring Boot的啟動器類加載器LaunchedURLClassLoader首先會讀取MANIFEST.MF中的附加屬性,如Start-Class(標識應用的實際主類)和Spring-Boot-Lib(指向內部依賴庫的位置)。
圖片
圖片
啟動類加載器工作流程如下:
Spring Boot的啟動器和加載器機制有效地實現了對自包含jar包的管理和執行,我們無需關心復雜的類路徑配置和依賴加載,只需通過一個簡單的命令即可啟動一個完整、獨立運行的應用程序。
Spring Boot的一大特色就是能夠無縫整合并內嵌多種輕量級Web容器,比如:Apache Tomcat、Jetty、Undertow以及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三個注解的功能。其中
通過上述機制,Spring Boot能夠智能識別項目依賴、自動配置Bean,并結合類路徑掃描確保所有相關的組件和服務都被正確地初始化和管理,我們就可以專注于業務邏輯的開發,而不必過多考慮基礎設施層面的配置問題。
Spring Boot 應用程序被打包成的jar包之所以可以直接通過 java -jar 命令運行,是因為Spring Boot在構建過程中做了一些特殊的設計和配置。具體原因:
Spring Boot通過精心設計的打包流程和啟動器類,使得生成的jar包可以直接作為一個獨立的應用程序運行,極大地簡化了部署和運維復雜度。
本文鏈接:http://www.www897cc.com/showinfo-26-81054-0.html字節二面:為什么SpringBoot的 jar 可以直接運行?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: NPM 依賴管理的復雜性
下一篇: 我們一起聊聊軟件架構伸縮性法則