Springboot3 的一些新特性

本文介绍了SpringBoot3.0的重要更新,包括升级Java版本要求、迁移到JakartaEEAPI、自动配置包位置变化、GraalVM原生镜像支持以及SpringAOT处理。还提到了内嵌配置属性的变化和测试过程的调整。
摘要由CSDN通过智能技术生成

Springboot3 的一些新特性

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Release-Notes

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide

环境要求

Springboot3.0.5 对java版本最低要求为java17,并向上兼容到java20,spring 版本要求为6.0.7+,maven 版本要求为3.5+,Servlet 版本要求为5.0+,Servlet5.0 对应Tomcat10.0。

参考:https://docs.spring.io/spring-boot/docs/3.0.5/reference/html/getting-started.html#getting-started.system-requirements

Java EE --> Jakarta EE

2017 年,Oracle 宣布将Java EE 捐赠给了Eclipse 基金会,但Oracle 不允许其使用Java 商标,于是社区将Java EE 改名了为Jakarta EE。于是javax 包变更为了 jakarta 包。Springboot3 已经将所有的Java EE 迁移到了 Jakarta EE 。

Spring Boot 3.0 has migrated from Java EE to Jakarta EE APIs for all dependencies. Wherever possible, Jakarta EE 10 compatible dependencies have been chosen, including:

  • Jakarta Activation 2.1
  • Jakarta JMS 3.1
  • Jakarta JSON 2.1
  • Jakarta JSON Bind 3.0
  • Jakarta Mail 2.1
  • Jakarta Persistence 3.1
  • Jakarta Servlet 6.0
  • Jakarta Servlet JSP JSTL 3.0
  • Jakarta Transaction 2.0
  • Jakarta Validation 3.0
  • Jakarta WebSocket 2.1
  • Jakarta WS RS 3.1
  • Jakarta XML SOAP 3.0
  • Jakarta XML WS 4.0

https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api
https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api

如上是servlet API jar包的变更

自动配置包位置改变

Spring Boot 2.7引入了一个用于注册自动配置的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,同时还兼容了原先的spring .factories中的自动配置内容。在Spring Boot 3.0中,原先的spring .factories中的自动配置内容已经被移除,其他的配置没有变化。
在这里插入图片描述
第一张图是springboot2.2的,第二张图是springboot3.0.5的

支持GraalVM原生镜像(Native Image)

GraalVM

GraalVM是一个高性能的JDK。GraalVM可以提前将Java应用程序编译成可执行的二进制文件(GraalVM原生镜像)。与运行在Java虚拟机(JVM)上的应用程序相比,这些二进制文件更小,启动速度更快,在没有预热的情况下提供峰值性能,并且使用更少的内存和CPU

GraalVM减少了应用程序的攻击面。它从应用程序二进制文件中排除未使用的类、方法和字段。它将反射和其他动态Java语言特性限制为仅在构建时使用。它不会在运行时加载任何未知代码。

GraalVM的原生镜像是一个完整的、特定于平台的可执行文件,不需要java的运行环境即可运行。

GraalVM与原生JVM的区别

GraalVM提前将java代码编译成机器码,这就导致了其与原生的java运行环境有一些差异。主要的区别是:

  • 应用程序的静态分析是在构建时从主程序的入口点执行的,也就是会扫描所有主程序可以访问的方法。所以,在创建可执行二进制文件时无法访问的代码将被删除,并且不会成为可执行文件的一部分。

  • GraalVM不能直接感知代码中的动态元素,必须告诉它反射、资源、序列化和动态代理。

  • 应用程序类路径在构建时是固定的,不能更改。

  • 没有延迟类加载,可执行文件中的所有内容将在启动时加载到内存中。

Spring Ahead-of-Time(AOT) Processing

基于GraalVM与原生JVM的区别,在构建生成原生镜像之前,Spring会执行一些提前处理,并生成GraalVM可以使用的额外资源。Spring AOT处理生成的额外资源通常包含:

  • Java源代码

  • 字节码(用于动态代理等) :

  • GraalVM JSON提示文件:

    • 资源提示(Resource -config.json)

    • 反射提示(reflect-config.json)

    • 序列化提示(Serialization -config.json)

    • Java代理提示(Proxy -config.json)

    • JNI提示(JNI -config.json)

Java源代码
//原生的java源代码
@Configuration(proxyBeanMethods = false) 
public class MyConfiguration {

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }

}

原生的spring ioc 容器,是扫描指定包下的所有文件,首先生成BeanDefinition,然后再利用反射生成Bean。Spring Ahead-of-Time Processing 将BeanDefinition的生成提前,MyConfiguration 类生成的Java 源代码示例如下:

/**
 * Bean definitions for {@link MyConfiguration}.   经过spring aot 处理得到的java源代码
 */
public class MyConfiguration__BeanDefinitions {

    /**
     * Get the bean definition for 'myConfiguration'.
     */
    public static BeanDefinition getMyConfigurationBeanDefinition() {
        Class<?> beanType = MyConfiguration.class;
        RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
        beanDefinition.setInstanceSupplier(MyConfiguration::new);
        return beanDefinition;
    }

    /**
     * Get the bean instance supplier for 'myBean'.
     */
    private static BeanInstanceSupplier<MyBean> getMyBeanInstanceSupplier() {
        return BeanInstanceSupplier.<MyBean>forFactoryMethod(MyConfiguration.class, "myBean").withGenerator(
                (registeredBean) -> registeredBean.getBeanFactory().getBean(MyConfiguration.class).myBean());
    }

    /**
     * Get the bean definition for 'myBean'.
     */
    public static BeanDefinition getMyBeanBeanDefinition() {
        Class<?> beanType = MyBean.class;
        RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
        beanDefinition.setInstanceSupplier(getMyBeanInstanceSupplier());
        return beanDefinition;
    }

}

当使用Maven时,生成的Java 源代码可以在target/spring-aot/main/sources中找到,使用Gradle时可以在build/ Generated /aotSources中找到。

字节码(用于动态代理等)

spring AOP生成代理类使用了直接生成字节码的cglib库。

当应用程序在JDK上运行时,代理类在应用程序运行时动态生成。在创建原生镜像时,需要在构建时创建这些代理,以便GraalVM可以包含它们。

生成的字节码文件可以在Maven的target/spring-aot/main/classes和Gradle的build/generated/aotClasses中找到它们。

GraalVM JSON提示文件

Spring AOT Processing还将生成GraalVM使用的提示文件。提示文件一般是JSON数据,这些数据描述了GraalVM应该如何处理通过直接检查代码无法理解的事情,GraalVM生成Native image时会自动拾取它们。

当使用Maven时,生成的GraalVM JSON提示文件可以在target/spring-aot/main/resources中找到,而使用Gradle时可以在build/ Generated /aotResources中找到。

如果我们需要为反射、资源、序列化、代理使用等提供一些自定义的提示,可以使用RuntimeHintsRegistrar API。创建一个实现RuntimeHintsRegistrar接口的类,然后对提供的RuntimeHints实例进行适当的调用。然后,在任何@Configuration类(例如@SpringBootApplication注解)上使用@ Importuntimehints来激活这些提示。

public class MyRuntimeHints implements RuntimeHintsRegistrar {

    @Override
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
        // Register method for reflection
        Method method = ReflectionUtils.findMethod(MyClass.class, "sayHello", String.class);
        hints.reflection().registerMethod(method, ExecutableMode.INVOKE);

        // Register resources
        hints.resources().registerPattern("my-resource.txt");

        // Register serialization
        hints.serialization().registerType(MySerializableClass.class);

        // Register proxy
        hints.proxies().registerJdkProxy(MyInterface.class);
    }

}

内嵌的配置属性失效

反射提示是由Spring AOT引擎为配置属性自动创建的。然而,自定义类的嵌套配置属性必须用@NestedConfigurationProperty注解,否则它们将不会被检测到,也不会被绑定。

测试

mvn springboot:process-aot   # 对应Spring Ahead-of-Time Processing 的过程

在这里插入图片描述

mvn -Pnative native:build -f pom.xml  # 编译生成可执行文件(native image)

在这里插入图片描述

原生的JavaGraalVM
编译耗时3.916s2min11s
启动耗时0.88s0.055s

可以看到GraalVM Native Image 启动的耗时比原生的Java快了有一个数量级,但编译的耗时比较长。

原生的JVM 编译指的是由源代码生成jar包的过程,而GraalVM 是指源代码生成可执行文件。

此部分参考:https://docs.spring.io/spring-boot/docs/3.0.0/reference/html/native-image.html#native-image.introducing-graalvm-native-images.understanding-aot-processing.source-code-generation

springboot3.0 的demo的源码,主要测试了反射、AspectJ还有@NestedConfigurationProperty注解。地址:https://gitee.com/ji-hang/springboot3-demo

  • 42
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值