自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

SpringBoot.3中的aot.factories到底有什么用?和以前的spring.factories一樣嗎?

開發(fā) 前端
在探索 aot.factories? 和 spring.factories 的過程中,我們不僅揭示了這兩個文件的本質(zhì)差異,還深入探討了它們在 Spring Boot 3 中的作用及其應(yīng)用場景。

首先,我們來澄清一下 aot.factories 和 spring.factories 之間的區(qū)別。這兩個文件不僅名稱不同,而且在功能上也存在顯著差異。接下來,我們將深入探討這兩個文件的具體作用以及它們各自的應(yīng)用場景。讓我們一起來揭開它們的神秘面紗吧!

在我們上一次討論 Spring Boot 3 版本時,我們關(guān)注了它的加載機制并注意到了一些小的變化。嚴(yán)格來說,這些變化主要體現(xiàn)在文件名稱的調(diào)整上:原本的 META-INF/spring.factories 文件已經(jīng)遷移至新的位置,即 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。

想要了解更多詳細信息,歡迎查閱這篇文章:https://www.cnblogs.com/guoxiaoyu/p/18384642

問題來了

要深入了解 Spring Boot 的加載機制,首先需要認識到每個第三方依賴包實際上都包含自己獨特的 META-INF/spring.factories 文件。正如圖中所示。

這些文件在應(yīng)用程序啟動時扮演著重要的角色,它們定義了自動配置的類和其他相關(guān)設(shè)置,幫助 Spring Boot 在運行時自動識別和加載相應(yīng)的配置。

圖片圖片

然而,當(dāng)我們試圖查看某個第三方依賴包時,可能會發(fā)現(xiàn)找不到相應(yīng)的 META-INF/spring.factories 文件,甚至沒有 *.imports 文件,這時該怎么辦呢?不要慌張!并不是所有的項目都具備自動配置功能。例如,ZhiPuAiAutoConfiguration 的自動配置實際上已經(jīng)包含在 Spring Boot 的核心庫中。

@AutoConfiguration(after = { RestClientAutoConfiguration.class, SpringAiRetryAutoConfiguration.class })
@ConditionalOnClass(ZhiPuAiApi.class)
@EnableConfigurationProperties({ ZhiPuAiConnectionProperties.class, ZhiPuAiChatProperties.class,
        ZhiPuAiEmbeddingProperties.class, ZhiPuAiImageProperties.class })
public class ZhiPuAiAutoConfiguration {
}

可以簡單理解為,一旦你引用了相應(yīng)的依賴包,它們的配置便會立即生效。然而,在查找配置的 *.imports 文件時,我發(fā)現(xiàn)了一個有趣的現(xiàn)象:許多依賴包下也存在 aot.factories 文件。這是用來做什么的呢?考慮到 Spring Boot 自身也包含此類文件,這表明這個概念并非無的放矢。

因此,帶著這個疑問,我決定深入探究其背后的機制與作用。

一探究竟

經(jīng)過了一番 AI 問答和上網(wǎng)搜索,我大致了解了 aot.factories 文件的用途:它實際上是為打包和編譯服務(wù)的。這個文件可以幫助將 Java 項目打包成可執(zhí)行的 EXE 文件(在 Windows 系統(tǒng)下,其他操作系統(tǒng)則有不同的打包方式),這樣就無需依賴 Java 運行環(huán)境即可直接運行。不過,這與 Spring Boot 的自動配置機制并沒有直接關(guān)系。

那么,為什么會發(fā)明這樣的東西呢?我知道你很著急,但是你先別著急!聽我一點一點講,你就更明白了!

Java當(dāng)前痛點

有過 Java 開發(fā)經(jīng)驗的朋友們應(yīng)該都知道,以前的 Java 應(yīng)用通常都是單體架構(gòu),這意味著啟動一個項目往往需要耗費幾分鐘的時間,尤其是大型項目,啟動時間更是讓人頭疼。因此,隨著技術(shù)的發(fā)展,微服務(wù)架構(gòu)應(yīng)運而生,不僅顯著縮短了啟動時間,而且將業(yè)務(wù)邏輯進行了合理的切分。

然而,微服務(wù)架構(gòu)也并非沒有缺點。盡管啟動速度更快,項目在啟動后往往無法立即達到最佳的運轉(zhuǎn)狀態(tài),也就是說,應(yīng)用需要一段時間才能進入高效的運行峰值。

因為 Java 的底層通常使用的是 HotSpot 虛擬機,HotSpot 的運行機制是將常用的代碼部分編譯為本地(即原生)代碼。這意味著在程序啟動之初,HotSpot 并不知道哪些代碼會成為“熱點”代碼,因此無法立即將這些代碼轉(zhuǎn)換為機器能夠直接理解和執(zhí)行的形式。

在這個過程中,HotSpot 會不斷分析和監(jiān)測代碼的執(zhí)行情況,以快速識別出哪些部分是頻繁被調(diào)用的。只有在識別出熱點代碼并將其編譯為本地代碼之后,我們的項目才能實現(xiàn)最佳的吞吐量。

要想讓 Java 像 Python 那樣實現(xiàn)瞬時啟動,幾乎是不可能的。這一現(xiàn)象使得 Java 在很多情況下更適合用于企業(yè)級服務(wù),主要原因在于其所追求的穩(wěn)定性和可靠性。在企業(yè)環(huán)境中,系統(tǒng)的穩(wěn)定性往往是首要考慮的因素。

然而,Java 也面臨著一系列挑戰(zhàn),這些挑戰(zhàn)在云計算時代尤為突出。

云時代

以 Serverless 為例,Serverless 是一種在云計算環(huán)境中日益成為主流的部署模式。它通過將基礎(chǔ)設(shè)施的管理和運維任務(wù)抽象化,使開發(fā)者能夠更加專注于業(yè)務(wù)邏輯的實現(xiàn),而不必過多關(guān)注底層的資源配置和管理。

圖片圖片

我就不提以前那種需要自己部署物理機的老年代的情況了。如今,絕大多數(shù)公司都已經(jīng)采用了 Kubernetes(K8s)作為集群管理的解決方案。在各大云服務(wù)提供商處購買服務(wù)器后,企業(yè)通常會自行管理其集群服務(wù)。運維團隊則負責(zé)監(jiān)控和優(yōu)化資源配置,及時進行擴展以滿足需求。

此外,隨著技術(shù)的發(fā)展,Server Mesh 和邊車模式也逐漸興起,這些都是值得深入了解的概念。歸根結(jié)底,這些改進的目的就是為了顯著節(jié)省公司內(nèi)部的開發(fā)時間,從而讓團隊能夠更專注于核心業(yè)務(wù)。

目前的 Serverless 架構(gòu)顯著提高了資源利用的效率,因為所有的基礎(chǔ)設(shè)施管理工作都由云服務(wù)提供商負責(zé)。實際上,云廠商的基礎(chǔ)設(shè)施本身并沒有發(fā)生根本變化,變化的主要是架構(gòu)設(shè)計,使得客戶的使用體驗更加便捷和高效。在這種模式下,無論是運維人員還是開發(fā)人員,都只需關(guān)注函數(shù)的部署,而無需深入了解服務(wù)器的細節(jié)信息。

開發(fā)者不再需要關(guān)心函數(shù)的運行方式、底層有多少容器或服務(wù)器在支撐這些服務(wù)。對他們而言,這一切都被抽象化為一個簡單的接口,只需確保參數(shù)對接得當(dāng)即可。

但是,你敢用 Java 來部署 Serverless 函數(shù)嗎?當(dāng)系統(tǒng)的吞吐量急劇上升,需要迅速啟動一個新節(jié)點來支撐額外的負載時,這位 Java 大哥可能還在忙著啟動或者進行預(yù)熱,這可真是耽誤事??!所以Java作為牛馬屆的老大哥怎么可能會愿意當(dāng)小弟?

GraalVM 簡介

如果你還不熟悉 GraalVM,但一定聽說過 OpenJDK。實際上,它們都是完整的 JDK 發(fā)行版本,能夠運行任何面向 JVM 的語言開發(fā)的應(yīng)用。不過,GraalVM 不僅限于此,它還提供了一項獨特的功能——Native Image 打包技術(shù)。這項技術(shù)的強大之處在于,它能夠?qū)?yīng)用程序打包成可以獨立運行的二進制文件,這些文件是自包含的,完全可以脫離 JVM 環(huán)境運行。

換句話說,GraalVM 允許你創(chuàng)建類似于常見的可執(zhí)行文件(如 .exe 文件)的應(yīng)用程序,這使得部署和分發(fā)變得更加簡便和靈活。

圖片圖片

如上圖所示,GraalVM 編譯器提供了兩種模式:即時編譯(JIT)和提前編譯(AOT)。AOT全稱為Ahead-of-Time Processing。

對于 JIT 模式,我們都知道,Java 類在編譯后會生成 .class 格式的文件,這些文件是 JVM 可以識別的字節(jié)碼。在 Java 應(yīng)用運行的過程中,JIT 編譯器會將一些熱點路徑上的字節(jié)碼動態(tài)編譯為機器碼,以實現(xiàn)更快的執(zhí)行速度。這種方法充分利用了運行時信息,能夠根據(jù)實際的執(zhí)行情況進行優(yōu)化,從而提高了性能。

而對于 AOT 模式,GraalVM 則在編譯期間就將字節(jié)碼轉(zhuǎn)換為機器碼,完全省去了運行時對 JVM 的依賴。由于省去了 JVM 加載和字節(jié)碼運行期預(yù)熱的時間,AOT 編譯和打包的程序具有非常高的運行時效率。這意味著在啟動時,應(yīng)用程序可以幾乎瞬間響應(yīng),極大地提高了處理請求的能力。

那么,這種 AOT 編譯到底有多快?它是否會成為 Serverless 函數(shù)的一種常用方案,超越 Python 等其他語言的應(yīng)用呢?為了驗證其性能優(yōu)勢,我們可以進行實際測試。

安裝GraalVM

我們大家基本上都在本地安裝了 IntelliJ IDEA 開發(fā)工具,使用起來非常方便。在這里,我們可以直接通過 IDEA 的內(nèi)置功能下載 GraalVM,省去了在官方網(wǎng)站上尋找和下載的時間。只需簡單幾步,我們就可以快速獲取到最新的 GraalVM 版本,隨時準(zhǔn)備進行開發(fā)。

下載完成后,我們只需配置項目的 JDK 為 GraalVM。由于我目前使用的是 JDK 17,因此需要選擇與之兼容的 GraalVM 17 版本。這種配置過程相對簡單,只需在項目設(shè)置中更改 JDK 路徑即可。

圖片圖片

我們將繼續(xù)使用之前研究過的 Spring AI 項目,在此基礎(chǔ)上,我們需要添加一些相關(guān)的 Spring Boot 插件。

<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
</plugin>

在我們順利完成所有配置后,準(zhǔn)備進行編譯時,卻意外地遇到了錯誤提示,顯示 JAVA_HOME 指向的是我們原本的 JDK 1.8。這一問題的出現(xiàn)主要是由于其中某個工具并不依賴于 IntelliJ IDEA 的啟動變量,而是直接讀取了 JAVA_HOME 的環(huán)境變量。

為了解決這個問題,我們需要確保 JAVA_HOME 環(huán)境變量正確指向我們新安裝的 GraalVM 版本。因此,我們必須在本地系統(tǒng)中下載并安裝 GraalVM,確保其版本與我們項目中所需的 JDK 版本相匹配。

首先我們找到官網(wǎng):https://www.graalvm.org/downloads/

圖片圖片

因為我是windows版本,所以自己請選擇好相應(yīng)的操作系統(tǒng)。等待下載完畢,解壓完成后,將配置環(huán)境變量指向改目錄后重啟生效,再次編譯即可。

運行后,還是報錯如下:Error: Please specify class (or/) containing the main entry point method. (see --help)

內(nèi)容就是找不到啟動類的意思,所以需要加一些配置。找了半天修改如下,切記前后順序別變,否則還是會有點問題。

<build>
        <plugins>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
                <configuration>
                    <!-- imageName用于設(shè)置生成的二進制文件名稱 -->
                    <imageName>${project.artifactId}</imageName>
                    <!-- mainClass用于指定main方法類路徑 -->
                    <mainClass>com.example.demo.DemoApplication</mainClass>
                    <buildArgs>
                        --no-fallback
                    </buildArgs>
                </configuration>
                <executions>
                    <execution>
                        <id>build-native</id>
                        <goals>
                            <goal>compile-no-fork</goal>
                        </goals>
                        <phase>package</phase>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

接下來,我們將繼續(xù)使用常用的 Maven 命令,如 mvn clean package,來進行項目的打包。這個過程可能會顯得有些漫長,尤其是與以前相比,打包速度似乎下降了不止一個級別。這次,我的打包過程持續(xù)了大約十分鐘,這確實比我之前的體驗慢了不少。

圖片圖片

然后非常激動的點擊了生成好的demo.exe文件,結(jié)果還是在報錯:

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.1)

Application run failed
org.springframework.boot.AotInitializerNotFoundException: Startup with AOT mode enabled failed: AOT initializer com.example.demo.DemoApplication__ApplicationContextInitializer could not be found
        at org.springframework.boot.SpringApplication.addAotGeneratedInitializerIfNecessary(SpringApplication.java:443)
        at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:400)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:334)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
        at com.example.demo.DemoApplication.main(DemoApplication.java:10)

然后經(jīng)過仔細查詢,需要指定profile為native,因為之前打的包沒有Aot信息。

圖片圖片

好的,又經(jīng)歷了15分鐘打包完畢,這次,我們終于成功了,我們可以直觀的看下AOT方式打包后的啟動時間與jar包方式的啟動時間對比。簡直是天壤之別。

圖片圖片

哦?確實,現(xiàn)在的啟動時間已經(jīng)縮短到毫秒級別,真令人驚訝!通過 GraalVM 的 Native Image 技術(shù),我們不僅實現(xiàn)了 Java 項目的快速啟動,還有效去除了傳統(tǒng) Java 應(yīng)用中的預(yù)熱時間。這一切看似都非常理想,然而,問題也隨之而來。

GraalVM 缺點

說完了 GraalVM 能解決 Java 原來的問題后,我們也必須認識到,它并非沒有缺點。如果沒有這些不足,大家對 GraalVM 的了解程度肯定會超過對 OpenJDK 的熟悉度。畢竟,既然它如此出色,為什么大多數(shù)人卻沒有廣泛使用呢?

首先,兼容性問題是一個顯著的挑戰(zhàn)。許多老舊版本的 JDK 項目根本無法與 GraalVM 兼容,這無疑限制了大部分企業(yè)的使用范圍。對于那些依賴于較舊 JDK 的企業(yè)而言,遷移到 GraalVM 可能需要耗費大量時間和資源,甚至面臨重構(gòu)代碼的風(fēng)險。

其次,即便是使用新版本 JDK 的項目,開發(fā)者們也往往對使用 GraalVM 感到猶豫。原因在于,GraalVM 對某些動態(tài)特性的支持相對較弱。例如,反射機制、資源加載、序列化以及動態(tài)代理等功能的限制,可能會對現(xiàn)有代碼的運行產(chǎn)生重大影響。這些動態(tài)行為在許多應(yīng)用程序中都是核心部分,任何對它們的削弱都可能導(dǎo)致功能缺失或性能問題。

有人可能會產(chǎn)生疑問:Spring 框架本身依賴于工廠模式和各種動態(tài)代理功能,若 GraalVM 不支持這些高級特性,豈不是意味著 Spring 的運行將受到致命影響?如果動態(tài)代理無法正常使用,Spring 的許多核心功能將會受到制約,那剛才提到的打包成功又是怎么回事呢?

實際上,這一切的背后得益于 GraalVM 提供的 AOT(Ahead-of-Time)元數(shù)據(jù)文件功能。這個特性使得開發(fā)者能夠在編譯階段明確哪些類和方法將會使用到動態(tài)代理,GraalVM 會在編譯時將這些信息整合到最終的可執(zhí)行文件中。

RuntimeHints與aot.factories

GraalVM 的 API —— RuntimeHints 負責(zé)在運行時收集反射、資源加載、序列化和 JDK 代理等功能的需求。這一特性為我們理解 GraalVM 如何支持動態(tài)特性提供了重要線索。實際上,大家在這里就可以猜到 aot.factories 文件的作用。沒錯,這個文件的存在正是為了在 GraalVM 編譯時,確保能夠加載 Spring 框架所需的 JDK 代理相關(guān)需求。我們看下文件:

org.springframework.aot.hint.RuntimeHintsRegistrar=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider.FreeMarkerTemplateAvailabilityRuntimeHints,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider.GroovyTemplateAvailabilityRuntimeHints,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.JacksonAutoConfigurationRuntimeHints,\
org.springframework.boot.autoconfigure.template.TemplateRuntimeHints

org.springframework.beans.factory.aot.BeanFactoryInitializatinotallow=\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingProcessor

org.springframework.beans.factory.aot.BeanRegistratinotallow=\
org.springframework.boot.autoconfigure.flyway.ResourceProviderCustomizerBeanRegistrationAotProcessor

org.springframework.beans.factory.aot.BeanRegistratinotallow=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer

我們可以注意到 RuntimeHintsRegistrar 的存在,它的主要作用是識別并加載所有實現(xiàn)了相關(guān)接口的類,從而進行解析和處理。需要強調(diào)的是,GraalVM 默認并不會自動查找 aot.factories 文件,因為這屬于 Spring 的特定機制。這就意味著,如果沒有顯式的指引,GraalVM 是無法主動識別和利用這些動態(tài)特性。

在 RuntimeHintsRegistrar 下面,我們還可以看到許多 AotProcessor 的實現(xiàn)。這個結(jié)構(gòu)和我們之前討論的 beanFactoryProcessor 有些相似,但這里我們不深入探討具體的細節(jié)。今天我們只聚焦于表面現(xiàn)象,以便理解其基本功能。

Spring 實際上已經(jīng)為我們解決了加載相關(guān)信息的問題,使得動態(tài)特性可以在編譯時得到適當(dāng)處理。然而,這并不意味著一切都已經(jīng)準(zhǔn)備就緒。第三方組件同樣需要提供相應(yīng)的實現(xiàn),以確保與 Spring 的兼容性。如果你的依賴庫使用了某些高級功能,但沒有實現(xiàn) Spring 的 aot.factories 掃描機制,那么這些功能在編譯后將無法生效。

因此,仍然有許多工作需要進行,以確保整個生態(tài)系統(tǒng)的兼容性和功能性。

總結(jié)

在探索 aot.factories 和 spring.factories 的過程中,我們不僅揭示了這兩個文件的本質(zhì)差異,還深入探討了它們在 Spring Boot 3 中的作用及其應(yīng)用場景。這一探索之旅引領(lǐng)我們進入了現(xiàn)代 Java 應(yīng)用開發(fā)的前沿,尤其是在 Serverless 和微服務(wù)架構(gòu)的背景下。隨著云計算的發(fā)展,應(yīng)用程序的性能與啟動速度已成為開發(fā)者的核心關(guān)注點。在此背景下,GraalVM 的出現(xiàn)提供了一種新穎的解決方案,通過其 Native Image 功能,Java 應(yīng)用的啟動時間得以大幅度縮短,這為開發(fā)者們帶來了巨大的便利。

然而,我們也意識到,雖然 GraalVM 提供了諸多優(yōu)勢,但它并非沒有挑戰(zhàn)。兼容性問題仍然是一個主要障礙,許多老舊 JDK 項目可能難以遷移到新平臺。此外,某些動態(tài)特性在 GraalVM 中的支持仍顯不足,這可能會影響到開發(fā)者在使用 Spring 框架時的靈活性與功能實現(xiàn)。尤其是在復(fù)雜的企業(yè)應(yīng)用中,這種影響可能更加明顯。

借助 Spring 框架與 GraalVM 的結(jié)合,開發(fā)者能夠享受更快的應(yīng)用啟動速度和更好的資源利用率,但同時也要做好充分的準(zhǔn)備,以應(yīng)對兼容性帶來的潛在問題。這意味著,隨著新技術(shù)的不斷涌現(xiàn),我們需要不斷地學(xué)習(xí)、適應(yīng)和優(yōu)化自己的開發(fā)流程。

責(zé)任編輯:武曉燕 來源: 靈墨AI探索室
相關(guān)推薦

2025-04-27 03:00:00

Spring技術(shù)接口

2025-04-01 08:08:29

2022-05-27 08:44:09

springStarter配置

2025-04-03 08:21:18

2022-07-29 08:25:02

volatileC語言原子

2023-01-13 16:57:50

SpringBoot配置核心

2023-09-07 23:06:07

2019-10-14 10:29:42

Java消息隊列

2024-02-28 16:18:41

2020-04-30 09:41:04

數(shù)據(jù)中臺CIO觀點

2020-10-20 09:57:04

量子計算人工智能技術(shù)

2022-05-24 12:57:49

函數(shù)代碼Java

2021-04-28 09:55:52

JavaLock接口并發(fā)編程

2019-05-16 10:30:49

JavaTCP協(xié)議

2023-11-08 08:47:34

Spring容器管理

2021-05-11 10:44:51

飛行模式通信設(shè)備通信干擾

2009-08-20 16:08:31

FCC美國寬帶計劃

2022-10-27 19:32:20

切片golang數(shù)組

2023-12-13 15:28:32

Python工具數(shù)據(jù)

2024-02-19 00:00:00

Python?starmap函數(shù)
點贊
收藏

51CTO技術(shù)棧公眾號