透過本篇文章您可以瞭解到以下內容:

  • Spring Native簡介
  • Spring Native深入剖析
  • 總結

Spring Native簡介

當我們看到Spring Native這個詞語的時候,是不是會有諸多疑問?  比如什麼是Spring Native,它是用來解決什麼問題的?  它和我們現在已經熟知的Spring Boot 以及Spring Cloud又有什麼連繫呢?

接下來就讓我們帶著這些疑問走進今天的文章,為您揭開Spring Native的面紗。

首先讓我們看看什麼是Spring Native

中文:

Spring Native可以使得Spring應用程式以GraalVM原生鏡像的方式進行運行。

與Java虛擬機相比,native image可以為許多類型的工作負載提供更經濟、更可持續的託管。 這些包括微服務、非常適合容器的功能工作負載和Kubernetes。

使用native image這種方式具備一些關鍵優勢,如即時啟動、即時峰值性能和減少記憶體消耗。

Spring Native的誕生意味著Spring除了支援常規的Java虛擬機以外,還可以支援使用GraalVM原生鏡像的方式進行運行。 從而提供了一種新的部署Spring應用程式的方法。

該項目的目標是孵化對Spring Native(Spring JVM的替代品)的支援,並提供旨在打包到羽量級容器中的本機部署選項。 實際上,目標是在這個新平臺上支援您的Spring應用程式,而對代碼層面是幾乎沒有修改的。 同時Spring Native 支援 Java 和 Kotlin。

令人鼓舞的是Spring Native專案是整個 Spring 團隊及其家族項目廣泛合作的結,例如我們眾所周知的Spring Framework、Spring Boot 以及 Spring Data、Spring Security、Spring Cloud等。

既然Spring Native支援以GraalVM原生鏡像的方式運行,那麼相比於JVM方式它的優點又有哪些呢?

概括起來可以理解為兩大方面,分別是對資源的消耗(記憶體)的減少以及應用啟動時間的縮短。

而對於應用啟動時間來說,可以理解為即時啟動(通常的情況下時間小於100ms),如下圖所示,基於Spring Boot的Web應用的簡單 例子,啟動時間僅為0.038s

在介紹完Spring Native的定義以及相比JVM的優勢以後,接下來讓我們看看Spring Native由哪些模塊組成 :

Spring-native

運行Spring Native所需的運行時依賴項,還提供了本機hints API。

彈簧原生配置

Spring AOT外掛程式使用的Spring類的配置提示,包括各種Spring Boot自動配置。

Spring原生文檔

Spring原生文檔,參考指南,採用asciidoc格式。

彈簧原生工具

spring原生工具:用於查看映像建構配置和輸出的工具。

Spring-aot

Maven和Gradle外掛程式公共的aot轉換基礎架構。

彈簧測試

測試特定的AOT基礎架構。

spring-aot-gradle-plugin 和 spring-aot-maven-plugin

顧名思義,AOT轉換的gradle和maven的外掛程式

樣品

包含各種範例,演示特性的使用,並用作集成測試。

透過上述的介紹,我們清楚了Spring Native的定義以及相比傳統JVM的優勢、同時瞭解了該專案包含了哪些模組。 那麼我們該如何嘗試使用Spring Native在我們的專案中呢?

在start.spring.io 中提供了快速集成創建基於Spring Native的方法,只需要添加相關Native的依賴即可。 如下圖所示:

值得注意的是對於Spring Native給出的標籤是DEVELOPER TOOLS。 如果把Spring Boot比作一輛汽車的話,那麼對於JVM運行的這種方式可以比作汽車的發動機引擎,而Spring Native的出現,正好是對現有的汽車在選擇發動機引擎時多了一種解決方案。

在對Spring Native有個初步認知以後,接下來讓我們深入的瞭解下Spring Native背後的故事。

Spring Native深入剖析

在上一小節中,我們談到了基於GraalVM native image的優勢(例如啟動時間快速,記憶體資源佔用少等),接下來讓我們看下Native image 與傳統常規的JVM的主要區別有哪些:

  • 在建構時從主入口點對應用程式進行靜態分析。
  • 未使用的零件將在建構時被移除。
  • 反射、資源和動態代理需要配置。
  • 類路徑在建構時是固定的。
  • 無類延遲載入,可執行檔中的所有內容都將在啟動時載入到記憶體中。
  • 一些代碼將在建構時運行。
  • Java應用程式的某些方面存在一些不完全支援的限制。

對於使用native image方式時,它的整個流程如下圖所示:

Native Image是一種將Java代碼提前編譯為獨立可執行檔的技術,執行檔包括應用程式類、依賴、運行時庫以及JDK靜態連接的本機代碼。 Graalvm通過子模組SubstrateVM來支援Native Image。

JDK位元組碼、對應的應用程式、第三方庫類庫共同組成了靜態編譯的輸入,此時SubstrateVM會對輸入進行靜態的分析, 並找到其中可達代碼,然後可達代碼將會有靜態編譯器進行編譯,最終得到native image。

在上面描述的整個流程中,Spring Native所適配的方面分為兩部分,分別是:

  • 生成應用程式上下文的優化版本
  • 根據需要推斷元數據

看到這裡,相信大家都會發現一個問題,那就是與傳統的JVM不同的是,類路徑在建構時已經是固定的,反射或資源需要進行配置,這裡沒有類似的懶載入機制 (可執行檔中包含的所有內容在啟動的時候都會載入進來)並且有些代碼可以在建構期調用。

為了充分擁抱這些特性,並允許Spring應用程式在本機上以最 大的相容性和最小的佔用空間運行,Brian Clozel 引入了 Spring 預先( ahead-of-time,AOT)轉換的 Maven 和 Gradle 外掛程式,這個外掛程式會對 Spring 應用執行預先轉換。

第一種轉換旨在基於推理引擎生成GraalVM本機配置(反射、資源、代理、本機映射選項)

對於一些本機配置無法推斷的情況,我們引入了本機提示註釋(更多詳細資訊,請參閱Javadoc),它允許Spring native以比常規基於JSON的本機映射配置更可維護、 類型安全和靈活的方式支援本機配置。 例如如下配置:

總結

回顧全篇內容,整體包括以下內容:

  • 在Spring Native深入剖析中,我們與傳統JVM方式進行了區別點的分析,接著介紹了關於native image建構的流程說明,最後介紹了 Spring 在其中做的內容又是哪些。

在下一篇文章中我們會對Spring 6.0以及Spring Boot 3.0進行深入的介紹,敬請期待!

參考連結:

  1. https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/#overview
  2. https://spring.io/blog/2021/03/11/announcing-spring-native-beta

作者簡介

李剛,VMware 大中華區應用現代化部門高級系統架構師,資深企業級軟體開發和軟體系統架構師。 Spring Cloud開源社區項目貢獻者、Netflix開源社區貢獻者。 近幾年,參與並主導了許多大型企業客戶的應用現代化數位轉型專案,涉及物流、製造、金融等諸多領域。 特別對微服務實現方法、現代化應用架構設計、雲原生實施落地、開源軟體技術等方面有著豐富經驗。