
Spring 在今年 3 月份推出了 Spring Native Beta 版本,我本來還想着等正式釋出了再研究下,不用等了,現在我們就來嘗嘗鮮。
https://spring.io/blog/2021/03/11/announcing-spring-native-betaSpring Native 簡介
我們都知道,傳統的 Spring 應用程式都是必須依賴于 Java 虛拟機(JVM)運作的,Spring Native 的誕生就是無需 JVM,它提供了另外一種運作和部署 Spring 應用的方式(目前隻支援 Java 和 Kotlin),通過 GraalVM 将 Spring 應用程式編譯成原生鏡像。
Spring Native 特點
1、無需 JVM 環境, Spring Native 應用程式可以作為一個可執行檔案獨立部署;
2、應用即時啟動,一般情況下應用啟動時間 < 100ms;
3、即時的峰值性能;
4、更少的記憶體消耗;
Spring Native 缺點
Spring Native 應用啟動那麼快也是有代價的,和 JVM 應用相比:
1、建構更笨重、建構時間更長;
2、更少的運作時優化;
3、很多 Java 功能受限;
4、很多特性還很不成熟;
Spring Native 應用場景
1、Spring Cloud 無伺服器化(Serverless);
2、以更廉價持久的方式運作 Spring 微服務;
3、非常适合 Kubernetes 平台,如:VMware Tanzu;
4、為 Spring 應用建立更佳的容器鏡像;
Spring Native 和 JVM 的差別
1、Spring Native 建構時會進行應用程式靜态分析;
2、Spring Native 建構時會移除未被使用的元件;
3、Spring Native 反射、資源、動态代理需要配置化;
4、Spring Native 建構時的 classpath 是固定不變的;
5、Spring Native 沒有類延遲加載,可執行檔案包含所有内容都在啟動時加載到記憶體;
6、Spring Native 建構時會運作一些代碼;
7、Spring Native 對于 Java 應用程式還存在一些局限性;
GraalVM 簡介
Spring Native 的核心就是 Oracle 的黑科技: GraalVM。
GraalVM 是一個由 Oracle 開發的全棧通用虛拟機,擁有高性能、跨語言互動等逆天特性,不僅支援了 Java、Scala、Groovy、Kotlin 等基于 JVM 的語言,以及 C、C++ 等基于 LLVM 的語言,還支援其他像 JavaScript、Ruby、Python 和 R 語言等,可提高多種語言的運作速度和吞吐量。
GraalVM 有以下幾個特性。
更加高效快速的運作代碼
能與大多數程式設計語言直接互動
使用 Graal SDK 嵌入多語言
建立預編譯的原生鏡像
提供一系列工具來監視、調試和配置所有代碼
具體就不介紹了,閱讀我之前分享的這篇文章:Oracle 釋出了一個全棧虛拟機 GraalVM
重點來看原生鏡像功能:
GraalVM 可以預編譯成原生鏡像,進而極大提速了啟動時間,并能減少 JVM 應用的記憶體占用。現在你知道為什麼 Spring Native 啟動那麼快的原因了!
Spring Native 正是通過 GraalVM 提供了對傳統 Spring 應用程式的輕量級運作方式,在不用修改任何傳統應用程式代碼的情況下,通過內建 Spring Native 項目就能輕松實作。
開始嘗鮮
建構 Spring Native 應用的兩種方式:
1、使用 Spring Boot Buildpacks 來生成一個包含原生可執行檔案的輕量級容器;
2、使用 GraalVM native image Maven 插件來生成一個包含原生可執行檔案;
本文使用第一種方式進行嘗鮮!
1、環境要求
這種方式需要安裝 Docker 環境:
Linux 需要配置非 root 使用者可運作
Mac 需要配置最大記憶體為 8G 或以上
因為我本地已經裝好了,這裡不再示範了,不會的點選這裡閱讀參考一下,或者關注公衆号:Java技術棧,在曆史文章中搜尋閱讀。
2、添加依賴
Spring Native 在 start.spring.io 上面已經可以開始使用了,在頁面上添加一個 "Spring Native" 依賴進去就好,如下所示:
Spring Boot:
注意依賴版本:
Spring Native 最新版本為:0.9.2,隻支援 Spring Boot 2.4.5
3、添加 Spring AOT 插件
添加 Spring AOT 插件:
<build>
<plugins>
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.9.2</version>
<executions>
<execution>
<id>test-generate</id>
<goals>
<goal>test-generate</goal>
</goals>
</execution>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Spring AOT 插件執行所需的提前轉換,以提升原生鏡像的相容性。
4、開啟原生鏡像支援
在 Spring Boot Maven 插件中增加以下配置:
本文所有代碼已上傳至:
https://github.com/javastacks/spring-boot-best-practice7、建構原生應用
Maven 插件建構指令:
mvn spring-boot:build-image
這個會建立一個 Linux 容器,使用 GraalVM 原生鏡像編譯器建構出原生應用程式,容器鏡像預設隻安裝在本地。
在 IDEA 插件中運作:
配置好後開始建構:
會看到大量這樣的錯誤,不用理會,這個會在未來移除。
最終建構完成,一個簡單的 Spring Boot 應用程式,這個建構卻過程花了我 4 分鐘。。
8、運作原生應用
使用平常運作 Docker 鏡像的方式就能運作原生應用:
docker run --rm -p 8080:8080
當然也可以在項目中編寫 docker-compose.yml 檔案的方式,這裡不再示範,感興趣的可以關注公衆号:Java技術棧,在曆史文章中搜尋閱讀 Docker 系列文章。
一般情況下,運作原生應用程式隻需要 100 毫秒以下,而運作基于 JVM 的應用程式大概需要 15 秒左右。
事實是否如此呢,一起來看看!
我天,82 毫秒就啟動了,啟動确實快。
再來通路我們之前寫的接口:
http://localhost:8080/native/hi![]()
王炸!!Spring 終于對 JVM 動手了… ![]()
王炸!!Spring 終于對 JVM 動手了… ![]()
王炸!!Spring 終于對 JVM 動手了… Docker 鏡像大小:80.7 M,而基于 JVM 運作的可執行 jar 包卻隻有不到 20M。![]()
王炸!!Spring 終于對 JVM 動手了…
這是因為原生鏡像不僅包含了應用程式中所使用到的來自 JDK、Spring 中的必須項,還包含了一個最小化的 OS 系統層,是以肯定是要比之前的要大不少。
總結
本文介紹了 Spring Native 的特點,及示範了基于 Docker 鏡像的原生應用。
本文所有示範代碼已上傳至:
感興趣的都可以 Star 下該倉庫,包含了之前寫的 Spring Boot 教程及示例源碼。
當然除了基于 Docker 鏡像,還可以使用原生鏡像 Maven 插件的方式,那種方式不需要 Docker,但需要安裝原生鏡像編譯器 GraalVM,道理是一樣的,這裡就不再示範了,有興趣的可以參考:
https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/#getting-started-native-image
如果有使用 Docker,那第一種肯定是更好的方式,所有的依賴都打包到一個鏡像中了,避免了環境污染。
最後總結一下就是,Spring Native 可以無需 JVM 運作,建構慢、啟動快、記憶體占用少、運作優化少,另外還有很多 Java 特性受限,比如:反射、動态代理等都需要通過提前配置化,因為 Java 是一種動态連結的語言,原生應用都要提前編譯,這個像反射、動态代理這種特性就會受限。
另外,目前 Spring Native 還處于 Beta 測試版本,現階段肯定還會存在很多問題,未來可能也還會有變更,不過我會繼續關注的,後續我也會更新更多 Java 系列最新技術實戰文章,公衆号Java技術棧第一時間推送。請大家持續關注哦!
本節所有内容都是參考官網最新文檔,可謂是做了第一個吃螃蟹的人,覺得我的文章對你用收獲的話,動動小手,給個在看、轉發,原創不易,棧長需要你的鼓勵。
版權申明:本文系公衆号 "Java技術棧" 原創,原創實屬不易,轉載、引用本文内容請注明出處,禁止抄襲、洗稿,請自重,尊重大家的勞動成果和知識産權,抄襲必究。