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"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章