Spring Framework 6.0.0-M3 中的初步 AOT 支援

工程 | Stéphane Nicoll | 2022 年 3 月 22 日 | ...

瞭解 Spring Native 實驗性專案的人都知道,Spring 團隊自 2019 年以來一直在為 Spring 應用提供原生映象支援。繼 2021 年 3 月 釋出首個 Beta 版 後,我們於 2021 年 12 月對 Spring Native 專案進行了 重大修訂

我們還在去年 SpringOne 大會上宣佈,我們打算在 2022 年將這項工作正式納入 Spring Framework 6.0。繼第三個里程碑版本釋出後,這篇博文將向您介紹已經包含的內容以及後續的計劃。

預先處理 (Ahead-Of-Time Processing)

預先處理應用上下文為最佳化打開了許多大門。根據具體上下文,我們可以減少隨應用釋出的底層設施數量,預先計算您在元件上宣告的某些特性以加快啟動時間,並識別在受限環境中可能出現問題的事項併為其提供替代方案。

Spring Framework 6.0.0-M3 釋出了基於 Spring Native 的第一批此類特性,並經過了廣泛審查並整合到核心容器中。它不是以附加模組的形式作為新特性,而是深度整合到現有核心模組中。目前包含:

  • 一個引擎,它針對給定的類路徑處理 ApplicationContext,並生成提供最佳化版本上下文的程式碼。
  • 一個新的 API 用於提供執行時提示 (runtime hints):整合者通常在自己的元件需要使用反射,或者需要訪問類路徑上的特定資源時會使用此 API。這些提示與 GraalVM 相容,我們提供了基礎設施來生成相應的配置檔案。

在構建時最佳化應用

當典型的 Spring 應用執行時,應用上下文會呼叫許多後處理器來準備 Bean 工廠:配置類解析、類路徑掃描以及其他最終可能觸發自動配置解析的處理器。一旦這些處理器執行完畢,在大多數情況下,它們在執行時就不再需要了。

在環境(類路徑等)定義清晰的情況下,這可以在構建時完全完成,以便只有與當前環境相關的 Bean 定義被貢獻到 Bean 工廠。在構建時執行的後處理器會被丟棄,並由它們貢獻的程式碼替代。

有許多方法可以“預先”貢獻程式碼,從註解處理到位元組碼生成。我們選擇讓新引擎生成 Java 原始碼,並在構建期間將其貢獻給應用。我們相信這在開發者體驗和最佳化機會之間取得了恰當的平衡。

這不僅應以熟悉和透明的方式支援原生用例,我們還相信這將在未來為普通的 JVM 應用帶來好處。例如,AOT 引擎完全獨立於原生,因此您可以在 JVM 上驗證應用的最佳化版本是否正常工作。

執行時提示 (Runtime Hints)

與 JVM 不同,執行原生映象在某些場景下需要額外的配置。例如,如果您的程式碼透過反射呼叫方法,您需要進行說明,以便必要的底層設施被包含在原生映象中。或者,如果您需要讀取類的元資料(核心容器在啟動時經常這樣做),您需要將類的位元組碼包含進來,這可能導致映象大小顯著增加。

AOT 引擎將自動推斷啟動核心容器所需的所有提示。未來,我們希望這些提示會減少,這得益於 GraalVM 本身的改進,或者最佳化方面的變化使得它們不再需要。

測試考量

程式碼生成需要良好的測試支援。很容易貢獻無法編譯的程式碼,或者能編譯但無法達到預期結果的程式碼。我們一直在開發新的測試工具來幫助解決這個問題,您可以在當前私有的 spring-core-test 模組中找到它們。

簡而言之,這個基礎設施允許我們編譯程式碼(透過一個抽象層,使得我們可以在記憶體中提供原始碼),並執行斷言,其中生成的程式碼可以輕鬆檢索到。

假設我們為一些 Java 類生成了程式碼,並且入口點是 MyObject

TestCompiler.forSystem().withSources(sourceFiles)
        .compile(compiled -> {
    MyObject instance = compiled.getInstance(MyObject.class);
    // invoking + assertions
});

在我們的案例中,AOT 引擎生成一個實現 ApplicationContextInitializer 介面的入口點。這樣的基礎設施使我們能夠執行以下操作:

  • 配置應用上下文以測試特定功能
  • 在上下文中呼叫 AOT 引擎
  • 使用 TestCompiler 編譯我們生成的原始碼
  • 建立一個新的應用上下文,並應用生成的程式碼,檢視功能是否按預期執行

上面描述的關於生成的程式碼同樣適用於執行時提示。我們正在開發額外的測試工具,以驗證您貢獻的提示與執行時行為是否匹配。但這尚未包含在此里程碑版本中,請關注 #27981 獲取更多詳細資訊。

後續計劃

在下一個里程碑版本中,我們將繼續基於 Spring Native 的經驗構建核心基礎設施。過去在 Spring Native 中的針對特定 Spring 專案的定製將遷移到相應的專案本身,或者透過適應引擎開箱即用的支援而變得不再需要。

Spring Framework 6.0 只是第一步:我們打算在此基礎上繼續發展多年,這也將對 JVM 使用者產生積極影響。敬請期待!

獲取 Spring 時事通訊

訂閱 Spring 時事通訊保持聯絡

訂閱

搶佔先機

VMware 提供培訓和認證,助力您加速發展。

瞭解更多

獲取支援

Tanzu Spring 透過單一訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視全部