springboot

Spring Boot 3 新特性与 GraalVM AOT 编译

By AI-Writer 15 min read

Spring Boot 3 新特性与 GraalVM AOT 编译

Spring Boot 3.0 是自 2014 年发布 1.0 以来最大的一次升级,带来了 Spring Framework 6Jakarta EE 9+GraalVM 原生镜像三大核心变化。本文系统梳理这些变化以及它们对日常开发的影响。

Spring Boot 3 核心升级

Java 版本要求

Spring Boot 3.x 要求 JDK 17 最低,推荐 JDK 21 LTS。不再支持 Java 8、11、15、16。

plaintext
Java 8/11/17  →  Spring Boot 2.7.x
Java 17/21    →  Spring Boot 3.x(必须)

Jakarta EE 9+ 迁移

最大破坏性变更:所有 javax.* 命名空间迁移到 jakarta.*

java
// Spring Boot 2.x
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.validation.constraints.Email;
import javax.servlet.http.HttpServletRequest;

// Spring Boot 3.x
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.GeneratedValue;
import jakarta.validation.constraints.Email;
import jakarta.servlet.http.HttpServletRequest;

这意味着:

  • 第三方库(如 Hibernate Validator 7+、Spring Security 6+)必须使用 jakarta.* API
  • 旧项目的 javax.servletjavax.persistence 代码需要全面替换
  • Spring Boot 提供迁移工具spring-boot-properties-migrator 模块检测废弃配置
xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-properties-migrator</artifactId>
    <scope>runtime</scope>
</dependency>

HTTP 接口:从 Servlet 到 Flex(可选)

Spring Boot 3.x 开始支持 Spring WebFlux 作为 Servlet 的替代方案,提供响应式编程模型:

java
// 响应式接口(非阻塞)
@RestController
@RequestMapping("/api/users")
public class UserReactiveController {

    private final UserReactiveRepository userRepository;

    // 返回 Mono(单个值)或 Flux(多个值),不阻塞线程
    public UserReactiveController(UserReactiveRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GetMapping("/{id}")
    public Mono<User> getUser(@PathVariable Long id) {
        return userRepository.findById(id)
                .switchIfEmpty(Mono.error(new UserNotFoundException(id)));
    }

    @GetMapping
    public Flux<User> listUsers(@RequestParam(defaultValue = "10") int limit) {
        return userRepository.findAll().take(limit);
    }
}

GraalVM Native Image 概述

什么是 Native Image

传统 Java 应用启动流程:

plaintext
JVM 启动 → 类加载 → JIT 编译(热点代码)→ 正常运行
   ~2-3s        ~5-10s(视依赖数量)    毫秒级
总启动时间:通常 5-15 秒

GraalVM Native Image 通过 AOT(Ahead-of-Time)编译,在构建时将 Java 字节码编译为原生机器码:

plaintext
Native Image 构建(数分钟)→ 直接运行机器码
   无类加载、无 JIT 编译、无 JVM 运行时
总启动时间:毫秒级(通常 50-200ms)

同时,Native Image 的内存占用(heap)也比传统 JVM 低得多(无 Metaspace、无 JIT 缓存)。

适用场景

场景推荐
Serverless / Lambda / 函数计算✅ 强烈推荐(冷启动关键指标)
Kubernetes 频繁扩缩容✅ 推荐
长期运行的微服务❌ 不推荐(JIT 编译后性能更优)
依赖大量反射/动态代理的框架⚠️ 需要额外配置

Spring AOT 编译流程

Spring Boot 3.x 内置 GraalVM 支持,spring-boot-maven-plugin 提供了 native 目标:

xml
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layers>
            <enabled>true</enabled>
        </layers>
        <excludes>
            <!-- 排除不需要的依赖以减小镜像体积 -->
            <exclude>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </exclude>
        </excludes>
    </configuration>
</plugin>

构建流程

bash
# 安装 GraalVM(推荐通过 SDKMAN)
gu install native-image

# 构建 Native Image
./mvnw -Pnative native:compile

Hints 注册(反射/资源 hints)

GraalVM 无法自动推断反射、动态代理、资源文件的访问,需要显式声明:

java
// 方式1:使用 @RegisterReflectionForBinding(Spring Boot 3 推荐)
@Configuration
@ImportRuntimeHints(ReflectionHintsRegistrar.class)
public class JacksonHints {

    static class ReflectionHintsRegistrar
            implements RuntimeHintsRegistrar {

        @Override
        public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
            hints.reflection()
                 .forType(UserDto.class)
                 .withFields();  // 注册所有字段的反射访问
        }
    }
}

// 方式2:Spring Boot 自动注册
// Spring Boot 3.x 在 spring-aot 阶段自动检测并生成 hints
// 对于 JPA 实体、Jackson 序列化类等已自动处理

// 方式3:Hibernate Reactive 配置
// application-native.yml
spring:
  jpa:
    open-in-view: false  # 响应式场景必须关闭 OSIV

native-image.properties 配置文件

META-INF/native-image/ 目录下创建配置文件:

properties
# META-INF/native-image/com.example/demo/native-image.properties
Args=--initialize-at-build-time=org.slf4j \
     --initialize-at-build-time=org.apache.commons \
     --report-unsupported-elements-at-runtime \
     --enable-http=netty \
     -H:+ReportExceptionStackTraces

实战:构建 Native Image

安装 GraalVM

bash
# macOS
brew install graalvm/tap/graalvm-ce

# 或通过 SDKMAN
sdk install graalvm 23.0.0.r17-grl

# 验证
gu --version
# GraalVM 23.0.0 Build tool 64bit

# 安装 native-image 组件
gu install native-image

Spring Boot Native 构建配置

bash
# 方式1:Maven profile(推荐)
./mvnw -Pnative native:compile

# 方式2:Spring Boot Maven 插件
./mvnw spring-boot:native-image

# 方式3:使用 Spring Boot Buildpack(自动检测 native 构建)
./mvnw spring-boot:build-image
# 输出镜像可通过 docker images 查看

启动验证

bash
# 传统 JVM 启动
time java -jar target/demo.jar
# 启动时间:~3.2 秒

# Native Image 启动
time ./target/demo
# 启动时间:~0.08 秒(毫秒级)

Docker 多阶段构建 Native Image

dockerfile
# 1. 构建阶段(完整 JDK)
FROM eclipse-temurin:21-jdk AS builder
COPY . /app
WORKDIR /app
RUN chmod +x mvnw
RUN ./mvnw -Pnative native:compile

# 2. 运行阶段(极简镜像)
FROM eclipse-temurin:21-minimal:alpine
COPY --from=builder /app/target/demo /app/demo
EXPOSE 8080
ENTRYPOINT ["/app/demo"]

AOT 编译优势与限制

优势

  • 毫秒级启动:冷启动时间从 3-15 秒降至 50-500 毫秒
  • 更低内存占用:无 JIT 编译器、无 Metaspace,heap 可大幅缩小
  • 即时销毁:适合短生命周期场景(Serverless)

限制

  • 构建时间极长:Native Image 构建需要 3-10 分钟(JVM 启动只需 30 秒)
  • 不支持动态类加载:运行时 Class.forName() 可能失败
  • 反射需要预配置:需要显式注册 hints
  • 调试困难:编译错误难以定位

典型内存配置对比

yaml
# 传统 JVM
java:
  opts: "-Xms256m -Xmx512m -XX:MetaspaceSize=128m"

# Native Image(内存可大幅降低)
spring:
  native:
    # imageArgs: ["-Xms64m", "-Xmx128m"]  # 通常不需要预设

Spring Boot 3 其他新特性

Records 支持

java
// Spring Data JPA Repository 返回 record
@Query("SELECT new com.example.UserBrief(u.id, u.username) FROM User u WHERE u.status = ?1")
List<UserBrief> findBriefByStatus(UserStatus status);

// Web 层 DTO 使用 record
public record CreateUserRequest(
        @NotBlank String username,
        @Email String email,
        @Min(0) Integer age
) {}

构造器绑定改进

java
@ConfigurationProperties
@ConstructorBinding  // Spring Boot 3.3 开始可省略(默认启用)
public record MailProperties(
        @DefaultValue("localhost") String host,
        @DefaultValue("587") int port
) {}

可观测性增强

Spring Boot 3.x 引入 spring-boot-observability 模块,统一了 Micrometer、OpenTelemetry 等可观测性工具。

小结

  • Spring Boot 3.x 要求 JDK 17+,所有 javax.* 命名空间迁移到 jakarta.*
  • GraalVM Native Image 将启动时间从秒级降至毫秒级,内存占用显著降低
  • Spring AOT 编译流程自动处理大量反射/资源 hints,但仍需关注动态类加载场景
  • Native Image 最适合 Serverless 和频繁扩缩容的云原生场景,长期运行服务未必需要
  • Spring Boot 3.x 全面拥抱 Records构造器绑定,代码更简洁
#springboot #spring-boot-3 #graalvm #native-image #aot #jakarta-ee

评论

A

Written by

AI-Writer

Related Articles

springboot
#5

数据访问:JPA 与 MyBatis

Spring Data JPA 实体映射与 Repository 接口、MyBatis-Plus 增强用法、JdbcTemplate 原始查询、事务管理(@Transactional 传播行为与隔离级别)完整指南

Read More
springboot
#6

多环境配置与外部化配置

application-&#123;profile&#125;.yml 多环境切换、@ConfigurationProperties 强类型配置绑定、@Value 占位符、配置加密与自定义配置加载顺序

Read More
springboot
#4

RESTful API 与 Web 开发

掌握 @RestController、@RequestMapping 系列注解、@PathVariable/@RequestParam/@RequestBody 参数绑定、REST 风格 URL 设计、响应封装与 @Validated 参数校验

Read More