Spring GraalVM Native 0.6.0 釋出

工程 | Andy Clement | 2020年4月9日 | ...

Spring 團隊剛剛釋出了 spring-graalvm-native 專案的 0.6.0 版本。該專案旨在讓任何嘗試構建 Spring 應用的 GraalVM 原生映象的人更容易進行。

要深入瞭解 Spring 原生映象,請參閱Sébastien Deleuze 的 Devoxx 演講

在這篇博文中,我們將討論此後發生的變化,並向您指出一些關鍵資源,讓您可以嘗試!該專案位於 spring-projects-experimental github 組織下,表明它正在進行中,但我們提供了許多示例應用程式,展示了已經可以工作的各種技術,還有大量關於如何使用您自己的應用程式進行實驗的文件。

什麼是 GraalVM 原生映象?

簡單回顧一下,GraalVM 是一個涵蓋多種用途的傘形專案,但我們在此關注的關鍵方面是將 JVM 程式碼作為原生映象執行。一旦編譯成特定平臺的原生映象,應用程式應該具有非常快的啟動速度和更可靠的記憶體特性(沒有 JIT 在開始時導致記憶體尖峰)。

建立映象時,原生映象構建工具需要了解有關應用程式的資訊,例如載入了哪些資源,可能透過反射訪問哪些型別,以及型別是否可以在映象構建時安全地初始化或必須在執行時稍後初始化。這些資訊使原生映象工具能夠嘗試為應用程式構建一個最最佳化的映象。

實際上有幾種收集和傳遞這種配置的方法

  • 有些庫直接在其分發包中包含它,作為固定的 .json 檔案(例如 netty)
  • 第三方特性(在 GraalVM 中稱為 Feature)參與構建過程並計算資訊,然後透過 API 將其傳遞給原生映象。spring-graalvm-native 專案的一個關鍵方面就是它包含的 Feature。這個 Feature 理解 Spring Boot 應用程式如何執行,將這些知識應用於正在構建的特定應用程式,並將結果傳遞給原生映象構建過程。由於它可以在封閉世界的假設下執行,知道在構建映象時類路徑是完整/固定的,因此它可以做出非常動態的決策。
  • GraalVM 提供的一個 agent(代理)可以在應用程式正常執行期間(作為 JVM 應用程式)收集必要的配置資料,然後這些檔案會被後續的原生映象構建步驟讀取。

這些計算配置的方法各有優缺點。例如,agent 只能收集應用程式執行期間被執行的程式碼路徑資訊,但它肯定會建立一套精確的、最最佳化的所需配置(在資源/反射訪問方面)。另一方面,Feature 不會建立一個完全最最佳化的配置,因為它不執行應用程式,所以必須允許某些可能或可能不會執行的程式碼路徑,但作為構建過程的一部分,Feature 可以進行 Spring 特有的最佳化,例如提前評估條件配置。當原生映象構建執行時,整個類路徑是已知的,因此此時可以執行 @ConditionalOnClass 檢查,如果檢查失敗,則可以丟棄該配置,甚至在生成的映象啟動時也不會考慮它。

我們一直在這些方面努力工作,試圖改善生態系統,以便我們可以走向一個一切都能正常工作的世界。還有一些路要走!我們正在深入研究 Tomcat,使其配置像 netty 一樣易於獲取。與 GraalVM 團隊合作,我們一直在確保 Spring Boot 應用程式中沒有什麼會阻礙原生映象構建(需要在雙方進行修復),並改進 spring-graalvm-native feature,使其更好地理解更廣泛的 Spring 應用程式。我們還一直在幫助確保 agent 收集器沒有遺漏任何東西。我們目前正在與 GraalVM 團隊解決的 issues 實際跟蹤在此

自 Spring One Platform 2019 和 Devoxx 的演示以來,該 feature 對 Boot 的瞭解更多了,agent 遺漏的東西更少了,GraalVM 的相容性更好了,生成的映象尺寸更小了,映象構建時間也縮短了,我們還包含了更多展示已工作內容的示例專案。

我如何嘗試?

有許多示例專案在此,甚至包括 PetClinic(當然!),以及與示例相關的文件在此,說明如何使用它們。有使用 Netty、Tomcat、Spring MVC、Spring WebFlux、JPA、Spring Cloud Function、kotlin 等的示例。您可能會看到什麼?

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::
...
INFO: Started TomcatApplication in 0.044 seconds (JVM running for 0.62)

要將其應用於您自己的專案,文件描述了使用feature、使用agent,或使用兩者結合的混合模式的所有步驟。混合模式有時是兩全其美的選擇,因為 agent 可以捕捉到 feature 可能遺漏的內容,反之亦然。

當它不起作用時我該怎麼辦?

整個過程還沒有非常順暢,許多領域還需要更多工作。負責 feature 的團隊和 GraalVM 團隊一直在努力改進診斷功能,以便在出現問題時您仍然能夠取得進展並瞭解下一步該怎麼做。某個隨機應用程式第一次就能工作是不太可能的,但對於那些致力於解決問題的人來說,許多應用程式都可以工作。您的應用程式可能使用了我們測試中尚未遇到的庫。它可能使用了 feature 尚未了解的某些 Spring 行為。問題可能在映象構建時出現,也可能在編譯後的映象啟動時的執行時出現。此處有一個故障排除頁面,討論了一些常見問題以及如何解決它們。遇到其他問題?請在專案上提交 issue

spring-graalvm-native 專案內部有一個配置子專案,它試圖以易於擴充套件的形式封裝關於 Spring Boot 行為的知識。例如,它記錄了一個特定的匯入選擇器可能需要反射訪問特定的型別。feature 本身由這種封裝的知識驅動,如果您發現目前的知識不足,請隨時增強它並貢獻回專案以構建這些知識,請參閱擴充套件性指南

spring-graalvm-native 專案中還包含一些 substitution(替換),substitution 是 GraalVM 的一個術語,指在映象構建時對現有類進行更改,因為該類在原生映象中包含時當前執行不佳。隨著時間的推移,計劃仍然是消除這些 substitution,並與包含這些問題類的專案合作,使它們達到一種理想的形式,無論是在原生映象內部還是外部都能正常工作。

雖然 spring-graalvm-native 專注於 Spring,但顯然一個 Spring 專案通常會包含許多第三方依賴。其中許多還沒有包含必要的配置,因此我們的 feature 正在盡力“彌補”它們。只要有可能,我們的計劃仍然是與這些依賴提供者合作,幫助他們製作理想的原生映象配置,然後原生映象構建就會自動讀取這些配置。GraalVM agent 提供了一種很好的方法來嘗試處理缺少配置的程式碼。

前進的道路

所有工作都只在這個實驗性 feature 中進行嗎?遠非如此。Spring 中已經添加了許多增強功能,以確保在構建為原生映象時能正常執行。例如,在 Spring Framework 中,Spring Framework 5.2@ConfigurationproxyBeanMethods 屬性使得應用程式無需 CGLIB 代理即可執行(原生映象過程只支援 JDK 代理)。我們還在 Spring Boot 條件處理中重構了一些類載入,使用了不同的方法,因為 agent 無法捕捉到原來的載入形式。

更多此類增強功能將陸續推出。feature 還有更多需要學習的地方,同時在核心 Spring 中,仍有太多工作是在啟動時完成的,我們可以將其推到構建時進行,這將對構建的原生映象的記憶體需求產生重大影響。這些改進不僅將惠及構建為原生映象的應用程式,也將惠及在常規 JVM 上執行的應用程式。情況只會越來越好!感謝 GraalVM 團隊在此項工作中給予我們的支援。要跟蹤我們的進展,請關注該專案

訂閱 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

搶佔先機

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲取支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,僅需一次簡單訂閱。

瞭解更多

即將舉行的活動

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

檢視全部