Boot-Spring-与-3.0-加速应用性能的完美融合-GraalVM (bootstrap)
在 2023 年,SpringBoot 3.0 的发布标志着 Spring 框架对 GraalVM 的全面支持。此支持对 Spring 技术栈来说是一项重大补充。
GraalVM 概述
GraalVM 是一个高性能的多语言虚拟机,它提供了 Ahead-of-Time(AOT) 编译的功能,可以将用 Java 和其他语言编写的应用程序转换为特定操作系统和架构的原生代码。这一转换带来了显著的性能提升,特别是在应用程序的启动时间和内存占用方面。
GraalVM 与 SpringBoot 的集成
GraalVM 在 SpringBoot 中的集成体现了 Spring 团队对提升应用程序性能和优化资源使用的持续承诺。通过将应用程序编译为原生代码,GraalVM 消除了传统 Java 虚拟机(JVM)的解释器和即时编译器的开销,从而提高了应用程序的执行效率。这对于那些对性能和响应时间要求较高的应用程序尤为重要。
GraalVM 带来的优势
- 显著的性能提升
- 更快的启动时间
- 更低的内存占用
- 支持多语言开发
GraalVM 带来的挑战
尽管 GraalVM 带来了许多优势,但它也带来了一些挑战:
额外的配置和调整
GraalVM 的集成需要开发者对应用程序进行一些额外的配置和调整。由于 AOT 编译需要在构建时进行,因此开发者需要对应用程序的依赖和代码进行分析,并进行必要的修改。这可能会增加开发过程的复杂性和时间成本。
对复杂应用程序的支持限制
GraalVM 对于一些复杂的应用程序和框架的支持可能会有限。尽管 Spring 团队已经积极地推动 GraalVM 的集成,但某些特定的 Spring 功能和库可能需要进一步的优化和适配才能与 GraalVM 完全兼容。这需要 Spring 社区和开发者们的共同努力,不断改进和优化 Spring 与 GraalVM 的集成。
性能监测和调优
GraalVM 的使用也需要开发者对应用程序的性能和资源使用进行仔细的监测和调优。尽管 GraalVM 可以提供显著的性能提升,但不正确的使用和配置可能会导致性能下降或资源浪费。因此,开发者需要具备对 GraalVM 的深入了解,并进行必要的性能测试和调优,以确保应用程序能够充分发挥 GraalVM 的优势。
GraalVM 的机遇
尽管 GraalVM 的集成带来了一些挑战,但它也为 Spring 应用程序带来了许多机遇:
显著的性能提升
通过将应用程序编译为原生代码,GraalVM 可以显著提高应用程序的性能和响应时间,从而提升用户体验。
多语言开发
GraalVM 还支持多语言的开发,使开发者能够更灵活地选择适合其需求的编程语言。
未来展望
随着技术的成熟和社区的支持,预计 GraalVM 将在未来的 Spring 应用中发挥越来越重要的作用。Spring 团队将继续致力于优化 Spring 与 GraalVM 的集成,并提供更多的文档和指导,帮助开发者充分利用 GraalVM 的潜力。同时,开发者也需要跟进 GraalVM 的最新发展,学习和掌握相关的调优技巧和最佳实践,以确保应用程序能够充分发挥 GraalVM 的优势。
结论
GraalVM 的支持为 Spring 应用程序带来了显著的性能提升和更好的资源利用。它也带来了一些挑战,包括额外的配置和调整、对复杂应用程序的支持限制以及性能监测和调优的要求。通过充分了解 GraalVM 的特性和最佳实践,并与 Spring 社区和开发者们共同努力,我们可以充分利用 GraalVM 的潜力,提升 Spring 应用程序的性能和用户体验。
GraalVM实践image与spring-native
GraalVM是从main方法开始分析,所有可达的类和方法会被记录。
但是反射、动态代理、资源文件等无法通过简单的静态分析捕获,为了支持这部分代码的行为,GraalVM支持配置文件来支持JIT时常用的做法。
GraalVM推荐在“META-INF/native-image/”(或子文件夹,如为避免不同jar下的配置冲突,放在“META-INF/native-image/{groupId}/{artifactId}/”)下的来形成构建本地代码所需要的命令行参数。一般包含哪些类可以在构建时初始化(--initialize-at-build-time),哪些只能运行时初始化(--initialize-at-run-time)。
有被 JDK动态代理 的接口,可以记录到 ,比如MyBatis的SqlSession,Spring的Component等注解。
有 JNI 调用的类,可以记录到 ,比如。
有要被 反射 调用的,可以记录到 ,比如我们的Mapper要被MyBatis代理,要求Mapper接口的方法可以被反射查询到,参数和返回要被反射调用getter/setter来取值/设置值。
有 资源文件 ,可以记录到 ,比如这种国际化资源、这种应用配置以及MyBatis的Mapper文件等等。
还有序列化相关的,可以记录到。
这些配置文件可以通过GraalVM提供的 native-image-agent 来自动生成绝大部分内容:
然而,却不会自动生成,需要我们手动添加。如果不想使用默认的配置文件名,可以在修改文件名后(比如改成,甚至放在子文件夹下),使用参数告知graalvm。示例如下:
那么spring-native给我们带来了哪些便利呢?
spring-native提供了诸多 注解 ,帮助我们生成GraalVM所规范的配置。
比如InitializationHint注解可以生成里的--initialize-at-build-time”、“--initialize-at-run-time”。
比如JdkProxyHint注解可以生成的内容。
比如ResourceHint注解可以生成内容。
比如SerializationHint注解生成需要的序列化/反序列化内容。
比如TypeHint注解(明细配置可结合FieldHint和MethodHint)生成需要的哪些字段/方法可被反射调用。
介绍过开胃菜,接下来就是正式的大餐:IoC和AOP。
我们知道spring提供了xml、java代码、java注解等多种配置方式,帮助我们生成bean对象、查找并注入依赖、增强bean。而spring-boot提供了自动配置,开启约定大于配置,让我们无需在每次新建系统时重复配置。
spring-native针对这些功能,结合GraalVM的特点,为我们生成代码,来接好spring/spring-boot的岗位。spring-native会自动为每个存在依赖注入的包生成 ContextBootstrapInitializer 类,为每个类生成register前缀与类名组合的方法。方法内容大致可表示如下:
对于spring-boot的autoconfiguration,在满足条件时,同样生成ContextBootstrapInitializer。对于各个jar包下的文件,在“”下生成 StaticSpringFactories ,将类型和生成对象方式保存,以供后续使用。
在包下还生成了ContextBootstrapInitializer,与应用定义bean的不同之处在于,此类实现了ApplicationContextInitializer。
在 SpringApplication 构造时,通过生成的 SpringFactoriesLoader 加载类型及对应的对象(非AOT模式为加载,AOT模式为StaticSpringFactories),引起初始化,大致代码如下:
当然,并非所有的自动配置类其类型都是公开的(class XXAutoconfiguration,而不是public class XXAutoConfiguration),对于这种情况,spring-native为他们在同包名下生成_FactoryProvider类,该静态方法名为类型名,返回该类型。
还有些bean的类型,其构造函数是私有的,spring-native为其生成内部类来创建实例。
![Boot](https://tyye.cn/zb_users/theme/tpure/style/images/lazyload.png)
至此,当spring-boot的SpringApplication运行时,创建完DefaultBootstrapContext便由“”下的ContextBootstrapInitializer进行初始化,此时便会将各种bean及其生成方式注册到spring的上下文。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。