Spring Native Beta正式發佈,原生更香!

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"本文最初發表於"},{"type":"link","attrs":{"href":"https:\/\/spring.io\/blog\/2021\/03\/11\/announcing-spring-native-beta","title":"","type":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Spring博客網站"}]},{"type":"text","marks":[{"type":"strong"}],"text":",由InfoQ中文站翻譯分享。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最近,Spring發佈了"},{"type":"link","attrs":{"href":"https:\/\/github.com\/spring-projects-experimental\/spring-native","title":"","type":null},"content":[{"type":"text","text":"Spring Native"}]},{"type":"text","text":"的beta版本,該功能已經在"},{"type":"link","attrs":{"href":"https:\/\/start.spring.io\/","title":"","type":null},"content":[{"type":"text","text":"start.spring.io"}]},{"type":"text","text":"上可用了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這意味着,除了Spring誕生以來就支持的Java虛擬機,官方添加了使用"},{"type":"link","attrs":{"href":"https:\/\/www.graalvm.org\/","title":"","type":null},"content":[{"type":"text","text":"GraalVM"}]},{"type":"text","text":"將Spring應用編譯成"},{"type":"link","attrs":{"href":"https:\/\/www.graalvm.org\/reference-manual\/native-image\/","title":"","type":null},"content":[{"type":"text","text":"原生鏡像"}]},{"type":"text","text":"的beta支持,這樣的話,就能提供一種新的方式來部署Spring應用。Spring Native支持Java和Kotlin。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些原生的Spring應用可以作爲一個獨立的可執行文件進行部署(不需要安裝JVM),並且還能提供有趣的特徵,包括幾乎瞬時的啓動(一般會小於100毫秒)、瞬時的峯值性能以及更低的資源消耗,其代價是比JVM更長的構建時間和更少的運行時優化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/2c\/2c77a14f27da18f7e01951255b50ee3a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過簡單的"},{"type":"codeinline","content":[{"type":"text","text":"mvn spring-boot:build-image"}]},{"type":"text","text":"或"},{"type":"codeinline","content":[{"type":"text","text":"gradle bootBuildImage"}]},{"type":"text","text":"命令,就能生成一個優化的容器鏡像,它包含了一個最小的操作系統層和一個小的原生可執行文件,該文件只包含了必需的東西即JDK、Spring以及應用中所使用的依賴。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"請看下面這個最小的容器鏡像,它是一個50MB的可執行文件,包含了Spring Boot、Spring MVC、Jackson、Tomcat、JDK和應用本身。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/35\/356b16b40e9722d40b6ad743ceb76f68.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這種原生方式,在很多場景下都會對Spring應用產生價值:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用Spring Cloud Function的Serverless應用"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更廉價、更可持續地託管Spring微服務"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與"},{"type":"link","attrs":{"href":"https:\/\/tanzu.vmware.com\/","title":"","type":null},"content":[{"type":"text","text":"VMware Tanzu"}]},{"type":"text","text":"這樣的Kubernetes平臺有很好的契合性"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"想要最優的容器鏡像,以打包Spring應用和服務"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在使用場景上,比如Piotr Mińkowski提供了一個"},{"type":"link","attrs":{"href":"https:\/\/piotrminkowski.com\/2021\/03\/05\/microservices-on-knative-with-spring-boot-and-graalvm\/","title":"","type":null},"content":[{"type":"text","text":"非常棒的指南"}]},{"type":"text","text":",介紹瞭如何在"},{"type":"link","attrs":{"href":"https:\/\/knative.dev\/","title":"","type":null},"content":[{"type":"text","text":"Knative"}]},{"type":"text","text":"上使用Spring Boot和GraalVM構建原生微服務。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"團隊協作"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Spring Native beta是整個Spring團隊及其家族項目廣泛合作的結果:Spring Framework、Spring Boot還包括Spring Data、Spring Security、Spring Cloud和Spring Initializr。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"據悉,原生功能的工作範圍比Spring更廣,因爲原生涉及到更廣泛的JVM生態系統,所以官方一直在與GraalVM團隊合作,以改善原生鏡像的兼容性和資源消耗。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以下是來自GraalVM團隊的Vojin Jovanovic的一段話。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“與Spring團隊協作打造原生JVM生態系統是一件非常愉快的事情:他們深厚的技術知識,再加上對社區的敏感觸覺,總是能帶來最好的解決方案。最新的Spring Native版本,以及它在JVM生態系統中的衆多用法,爲原生編譯的廣泛採用鋪平了道路。”"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"支持的範圍"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,Spring Native已經從alpha版本畢業成爲beta,那麼很重要的一點就是明確它所支持的功能範圍。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Alpha版本是第一步,實驗了很多東西,並且基於一組樣例改善了Spring Native(之前叫做Spring GraalVM Native)的架構、兼容性和資源消耗,其中有很多破壞性的變更。官方還報告了"},{"type":"link","attrs":{"href":"https:\/\/github.com\/oracle\/graal\/labels\/spring","title":"","type":null},"content":[{"type":"text","text":"很多問題"}]},{"type":"text","text":",這些問題GraalVM團隊已經解決,從而減少JVM和Spring應用的原生鏡像之間的差距。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然它依然被認爲是實驗性的,但beta版意味着Spring現在在Spring生態系統的一個子集上提供了對原生的支持。如果你的應用正在使用業已支持的依賴,那麼你可以試用它,在出現問題時可以提bug或貢獻pull request。在最新的Spring Boot 2.x小版本的每個補丁發佈時,都會有一個新的Spring Native版本。Spring Native 0.9.0支持Spring Boot 2.4.3,Spring Native 0.9.1將支持Spring Boot 2.4.4等。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"start.spring.io"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Stéphane Nicoll在對"},{"type":"link","attrs":{"href":"https:\/\/start.spring.io\/","title":"","type":null},"content":[{"type":"text","text":"start.spring.io"}]},{"type":"text","text":"和相關IDE的集成中,引入了對Spring Native的支持,所以現在這是探索如何使用Spring構建原生應用最簡單的方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/06\/06295683cc0a2449970897438dc0c991.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"添加Spring Native依賴後將會使用所需的依賴和插件自動配置Maven或Gradle項目,以便於支持原生。應用代碼本身沒有變化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"請檢查自動生成的"},{"type":"codeinline","content":[{"type":"text","text":"HELP.md"}]},{"type":"text","text":"文件,該文件包含了有用的鏈接和文檔,同時它還能標記出來你是否選擇了一些在原生環境下不支持的依賴。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"預先轉換"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原生與JVM有所不同:類路徑在構建時是固定的,反射或資源需要進行配置,這裏沒有類的懶加載(可執行文件中包含的所有內容在啓動的時候都會加載進來)並且有些代碼可以在構建期調用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了充分擁抱這些特性,並且能讓Spring應用以最大的兼容性和最小的資源消耗運行在原生環境中,Brian Clozel在這個版本中引入了Spring預先(ahead-of-time,AOT)轉換的Maven和Gradle插件,這個插件會對Spring應用執行預先轉換。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一種轉換的目的是生成GraalVM原生配置(反射、資源、代理、原生鏡像選項),這是通過由Andy Clement設計和實現的一個特別棒的推斷引擎做到的,該引擎能夠理解Spring編程模型和基礎設施。例如,每個帶有@Controller註解的類,都會在生成的reflect-config.json文件中添加一個條目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有些原生配置是無法推斷的,對於這些情況,Spring Native引入了"},{"type":"link","attrs":{"href":"https:\/\/docs.spring.io\/spring-native\/docs\/current\/reference\/htmlsingle\/#native-hints","title":"","type":null},"content":[{"type":"text","text":"原生線索"}]},{"type":"text","text":"(native hint)註解(參見Javadoc以瞭解詳情),這些註解允許Spring Native支持原生配置,這種方式比常規的基於JSON的原生鏡像配置更加可維護、類型安全和靈活。例如,Spring Native對MySQL驅動支持就提供了線索註解,它們會在原生鏡像配置"},{"type":"codeinline","content":[{"type":"text","text":"reflect-config.json"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"resource-config.json"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"native-image.properties"}]},{"type":"text","text":"中生成正確的條目,如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"@NativeHint(\n trigger = Driver.class,\n options = \"--enable-all-security-services\",\n types = @TypeHint(types = {\n FailoverConnectionUrl.class,\n FailoverDnsSrvConnectionUrl.class,\n \/\/ ...\n }), resources = {\n @ResourceHint(patterns = \"com\/mysql\/cj\/TlsSettings.properties\"),\n @ResourceHint(patterns = \"com.mysql.cj.LocalizedErrorMessages\",\n isBundle = true)\n})\npublic class MySqlHints implements NativeConfiguration {}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"NativeConfiguration和其他的"},{"type":"link","attrs":{"href":"https:\/\/docs.spring.io\/spring-native\/docs\/current\/reference\/htmlsingle\/#how-to-contribute-dynamic-native-configuration","title":"","type":null},"content":[{"type":"text","text":"動態配置機制"}]},{"type":"text","text":"允許實現更加強大和動態化的配置生成,但是需要注意它們的API在未來的版本中可能會有很大變化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Spring開發人員也可以直接在@Configuration或@SpringBootApplication類上添加應用特定的原生線索註解,例如,對於使用"},{"type":"codeinline","content":[{"type":"text","text":"RestTemplate"}]},{"type":"text","text":"或"},{"type":"codeinline","content":[{"type":"text","text":"WebClient"}]},{"type":"text","text":"這樣的編程API序列化一個"},{"type":"codeinline","content":[{"type":"text","text":"Book"}]},{"type":"text","text":"類爲JSON:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"@TypeHint(types = Book.class)\n@SpringBootApplication\npublic class WebClientApplication {\n \/\/ ...\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在使用預先轉換系統時,最後一個,可能也是最強大的一個機制就是根據Spring Boot部署模型和GraalVM原生鏡像特徵所引入的封閉世界(closed-world)假設,它能夠自動生成針對原生環境進行優化的代碼。這裏的目標就是限制所需的外部原生配置的數量,從而提高兼容性,這是通過原生鏡像編譯器對代碼結構的分析實現的,同時還能通過減少反射、資源或代理所需的配置,降低資源佔用。一個具體的例子就是對各種"},{"type":"codeinline","content":[{"type":"text","text":"spring.factory"}]},{"type":"text","text":"(Spring Boot背後的擴展機制)的預先轉換,從而實現一個優化過的程序版本,該版本不需要反射並且會過濾掉應用上下文中不必要的條目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對Spring AOT來說,這只是一個開始,我們計劃添加更加強大的轉換,比如將"},{"type":"codeinline","content":[{"type":"text","text":"@Configuration"}]},{"type":"text","text":"替換爲函數式配置,從而通過預先分析替換運行時反射,能夠自動生成使用像lambda表達式和方法引用這種程序構造的配置類。這樣的話,就能允許GraalVM原生鏡像編譯器立即理解Spring配置,無需任何的反射配置或"},{"type":"codeinline","content":[{"type":"text","text":"*.class"}]},{"type":"text","text":"資源。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要記住的一個關鍵點是,在使用Spring Native時,這個AOT生成的代碼在JVM上也會默認使用,這樣的話能夠通過JVM允許的短反饋循環(short feedback loop),用調試器和所有常規工具實現“原生友好的代碼路徑”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管Spring AOT轉換目前主要是由原生場景需求驅動,但是有很多轉換並不是特定於原生場景的,有一些可能爲JVM上運行的Spring Boot應用提供優化。和往常一樣,對於這種主題,重要的是要以數據爲驅動,所以我們會衡量效率和性能來驅動我們的決策。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們很可能會完善IDE集成,目前請務必閱讀"},{"type":"link","attrs":{"href":"https:\/\/docs.spring.io\/spring-native\/docs\/current\/reference\/htmlsingle\/#_intellij_idea","title":"","type":null},"content":[{"type":"text","text":"相關文檔"}]},{"type":"text","text":",瞭解潛在的手動配置步驟,以便在IDE中運行應用程序之前更新生成的源碼。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"結論"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在支持原生方面,Spring有兩個支柱性的策略。第一個是在不需要對現有的數百萬個Spring Boot應用進行重大改動的情況下,對Spring基礎架構進行調整以適應原生。這包括在Spring頂層項目中爲實現原生友好而做出的改變,像@NativeHint這樣的基礎架構,以及在Spring Native中逐漸成熟的Spring AOT構建插件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二個支柱比Spring本身的範圍更廣,原生是一個與JVM特性有所差異的平臺,但Java生態系統需要儘可能地保持一致,以避免出現兩種截然不同的Java風格,如果這樣的話,將會是維護上的一個挑戰。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"https:\/\/spring.io\/blog\/2021\/03\/11\/announcing-spring-native-beta"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章