GraalVM Native Image với Spring Boot 3 năm 2026: Biên dịch AOT từng bước

Hướng dẫn đầy đủ để biên dịch ứng dụng Spring Boot 3 thành native image với GraalVM. Cấu hình AOT, tối ưu hóa và triển khai sản xuất.

GraalVM Native Image với Spring Boot 3: biên dịch AOT và tối ưu hiệu năng

Biên dịch native với GraalVM biến ứng dụng Spring Boot 3 thành tệp thực thi native. Thời gian khởi động giảm từ vài giây xuống còn vài mili giây và mức tiêu thụ bộ nhớ giảm rõ rệt. Hướng dẫn này bao quát mọi bước, từ cấu hình AOT đến triển khai sản xuất.

Yêu cầu cần có

GraalVM 22.3+ đã cài Native Image, Spring Boot 3.2+, cùng Maven hoặc Gradle. Biên dịch native cần nhiều RAM hơn (khuyến nghị tối thiểu 8 GB) và mất vài phút để hoàn tất.

Hiểu về AOT và biên dịch Native Image

Sự khác nhau giữa JIT và AOT

JVM truyền thống dùng cách biên dịch Just-In-Time (JIT): bytecode được thông dịch rồi biên dịch sang mã máy trong lúc chạy. GraalVM Native Image áp dụng hướng tiếp cận Ahead-Of-Time (AOT): toàn bộ mã được biên dịch trước khi chạy.

text
┌─────────────────────────────────────────────────────────────┐
│                    JIT Compilation                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   .java → .class → JVM → Interpretation → JIT → Machine    │
│                           (runtime)        (runtime)        │
│                                                             │
│   Advantages: Adaptive optimizations, fast class loading   │
│   Disadvantages: Slow startup, high memory consumption     │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                    AOT Compilation                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   .java → .class → GraalVM Native Image → Native executable │
│                    (build time)                              │
│                                                             │
│   Advantages: Instant startup, low memory footprint         │
│   Disadvantages: Long build, no dynamic reflection          │
└─────────────────────────────────────────────────────────────┘

Biên dịch AOT phân tích tĩnh toàn bộ mã có thể đạt tới từ điểm vào. Bất kỳ đoạn mã nào không được phát hiện ở thời điểm biên dịch sẽ bị loại khỏi native image, điều này giải thích các ràng buộc về reflection và nạp lớp động.

Kiến trúc Spring AOT

Spring Boot 3 tích hợp hỗ trợ AOT theo cách native. Quá trình biên dịch sinh thêm mã nguồn để thay thế cơ chế động bằng cơ chế tĩnh tương đương.

ApplicationConfig.javajava
// Standard Spring configuration
@Configuration
@EnableCaching
public class ApplicationConfig {

    @Bean
    public CacheManager cacheManager() {
        // Bean created dynamically at runtime in JIT mode
        // Pre-generated statically in AOT mode
        return new ConcurrentMapCacheManager("users", "products");
    }

    @Bean
    @ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")
    public FeatureService featureService() {
        // Conditions are evaluated at build time in AOT
        return new FeatureServiceImpl();
    }
}

Quá trình Spring AOT tự động sinh các tệp trong target/spring-aot/main:

text
target/spring-aot/main/
├── sources/                    # Generated Java code
│   └── com/example/
│       └── ApplicationConfig__BeanDefinitions.java
├── resources/
│   └── META-INF/
│       └── native-image/
│           ├── reflect-config.json    # Reflection configuration
│           ├── resource-config.json   # Included resources
│           └── proxy-config.json      # JDK proxies

Cấu hình dự án Spring Boot

Phụ thuộc Maven

Cấu hình Maven sử dụng plugin Spring Boot với profile native. Các phụ thuộc phải tương thích với GraalVM.

xml
<!-- pom.xml -->
<!-- Complete configuration for Spring Boot 3 Native -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.2</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>native-demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>21</java.version>
    </properties>

    <dependencies>
        <!-- Web starter with built-in native support -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- JPA with native-compatible Hibernate 6 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <!-- Native-compatible PostgreSQL driver -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- Validation with native hints -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        <!-- Tests with native support -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <!-- GraalVM plugin for native compilation -->
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <!-- Profile for native build -->
    <profiles>
        <profile>
            <id>native</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.graalvm.buildtools</groupId>
                        <artifactId>native-maven-plugin</artifactId>
                        <configuration>
                            <!-- Native build options -->
                            <buildArgs>
                                <!-- Size optimizations -->
                                <buildArg>-O2</buildArg>
                                <!-- Generate build report -->
                                <buildArg>--verbose</buildArg>
                                <!-- Enable HTTP/2 support -->
                                <buildArg>--enable-http</buildArg>
                                <buildArg>--enable-https</buildArg>
                            </buildArgs>
                            <!-- Memory for build -->
                            <jvmArgs>
                                <jvmArg>-Xmx8g</jvmArg>
                            </jvmArgs>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

</project>

Cấu hình Gradle tương đương

Với các dự án Gradle, cấu hình native được thực hiện tương tự thông qua plugin GraalVM native.

build.gradle.ktskotlin
// Gradle configuration for Spring Boot Native
plugins {
    java
    id("org.springframework.boot") version "3.4.2"
    id("io.spring.dependency-management") version "1.1.7"
    // GraalVM Native plugin
    id("org.graalvm.buildtools.native") version "0.10.4"
}

group = "com.example"
version = "1.0.0"

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    runtimeOnly("org.postgresql:postgresql")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

// Native build configuration
graalvmNative {
    binaries {
        named("main") {
            // Generated executable name
            imageName = "native-demo"

            // Compilation options
            buildArgs.addAll(
                "-O2",                    // Optimization level
                "--enable-http",          // HTTP support
                "--enable-https",         // HTTPS support
                "--verbose"               // Detailed logs
            )

            // Memory configuration for build
            jvmArgs.addAll("-Xmx8g")
        }

        named("test") {
            // Native tests with report
            buildArgs.add("--verbose")
        }
    }

    // Tracing agent for automatic discovery
    agent {
        defaultMode = "standard"
        enabled = true
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}
GraalVM Tracing Agent

Tracing agent (-agentlib:native-image-agent) tự động phát hiện các lời gọi reflection trong lúc chạy. Hãy chạy ứng dụng cùng agent, dùng qua mọi tính năng rồi sử dụng các tệp cấu hình đã sinh.

Quản lý reflection và tài nguyên

Cấu hình reflection thủ công

Một số thư viện sử dụng reflection theo cách mà phân tích tĩnh không phát hiện được. Lúc đó cần cấu hình thủ công.

src/main/resources/META-INF/native-image/reflect-config.jsonjson
// Configuration for classes requiring reflection
[
  {
    "name": "com.example.entity.User",
    "allDeclaredConstructors": true,
    "allDeclaredMethods": true,
    "allDeclaredFields": true
  },
  {
    "name": "com.example.dto.UserDTO",
    "allDeclaredConstructors": true,
    "allDeclaredMethods": true,
    "allDeclaredFields": true
  },
  {
    "name": "com.example.config.DynamicProperties",
    "methods": [
      { "name": "getValue", "parameterTypes": [] },
      { "name": "setValue", "parameterTypes": ["java.lang.String"] }
    ]
  }
]

Sử dụng Spring RuntimeHints

Spring Boot 3 cung cấp API lập trình để khai báo native hint, dễ bảo trì hơn so với tệp JSON.

NativeHintsRegistrar.javajava
// Programmatic registration of native hints
@Configuration
@ImportRuntimeHints(NativeHintsRegistrar.AppRuntimeHints.class)
public class NativeHintsRegistrar {

    static class AppRuntimeHints implements RuntimeHintsRegistrar {

        @Override
        public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
            // Register classes for reflection
            hints.reflection()
                // JPA entities with all members
                .registerType(User.class, MemberCategory.values())
                .registerType(Order.class, MemberCategory.values())
                // DTOs with constructors and getters/setters
                .registerType(UserDTO.class,
                    MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
                    MemberCategory.INVOKE_DECLARED_METHODS,
                    MemberCategory.DECLARED_FIELDS
                );

            // Register resources to include
            hints.resources()
                // Configuration files
                .registerPattern("application*.yml")
                .registerPattern("application*.properties")
                // Templates and static files
                .registerPattern("templates/*")
                .registerPattern("static/**/*")
                // Validation messages
                .registerPattern("ValidationMessages*.properties");

            // Register JDK proxies
            hints.proxies()
                .registerJdkProxy(
                    UserRepository.class,
                    Repository.class
                );

            // Serialization for caching
            hints.serialization()
                .registerType(User.class)
                .registerType(ArrayList.class);
        }
    }
}
EntityRuntimeHints.javajava
// Automatic hints for JPA entities
@Component
public class EntityRuntimeHints implements RuntimeHintsRegistrar {

    @Override
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
        // Automatic scan of entities in package
        ClassPathScanningCandidateComponentProvider scanner =
            new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));

        for (BeanDefinition bd : scanner.findCandidateComponents("com.example.entity")) {
            try {
                Class<?> entityClass = Class.forName(bd.getBeanClassName());

                // Register each entity for full reflection
                hints.reflection().registerType(
                    entityClass,
                    MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
                    MemberCategory.INVOKE_DECLARED_METHODS,
                    MemberCategory.DECLARED_FIELDS
                );

            } catch (ClassNotFoundException e) {
                // Log error without interrupting build
                System.err.println("Entity class not found: " + bd.getBeanClassName());
            }
        }
    }
}

Sẵn sàng chinh phục phỏng vấn Spring Boot?

Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.

Biên dịch và tối ưu hóa native image

Lệnh build

Biên dịch native được thực hiện với Maven hoặc Gradle. Quá trình mất vài phút và tiêu tốn nhiều tài nguyên.

bash
# Maven build with native profile
# Generates executable in target/
mvn -Pnative native:compile

# Gradle build
# Generates executable in build/native/nativeCompile/
./gradlew nativeCompile

# Build with native tests included
mvn -Pnative native:compile -DskipTests=false

# Build with tracing agent enabled
mvn -Pnative -Dagent=true test
mvn -Pnative native:compile

Tùy chọn tối ưu hóa nâng cao

Các tùy chọn biên dịch ảnh hưởng đến kích thước image, thời gian khởi động và hiệu năng lúc chạy.

xml
<!-- pom.xml -->
<!-- Advanced native build configuration -->
<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
    <configuration>
        <buildArgs>
            <!-- Optimization level (0-3, default: 2) -->
            <buildArg>-O3</buildArg>

            <!-- Optimization for startup time -->
            <buildArg>--pgo-instrument</buildArg>

            <!-- Executable compression (reduces size) -->
            <buildArg>-H:+CompressStrings</buildArg>

            <!-- Optimal garbage collector for containers -->
            <buildArg>--gc=serial</buildArg>

            <!-- Build time initialization -->
            <buildArg>--initialize-at-build-time=org.slf4j</buildArg>

            <!-- Debug symbols (disable in prod) -->
            <buildArg>-H:-IncludeAllTimeZones</buildArg>

            <!-- Detailed build report -->
            <buildArg>-H:+ReportExceptionStackTraces</buildArg>
            <buildArg>--verbose</buildArg>

            <!-- Monitoring support -->
            <buildArg>--enable-monitoring=heapdump,jfr</buildArg>
        </buildArgs>

        <!-- Quickbuild for development (faster, less optimized) -->
        <quickBuild>false</quickBuild>

        <!-- Fallback to jar if native fails -->
        <fallback>false</fallback>
    </configuration>
</plugin>
BuildTimeInitializer.javajava
// Build time initialization to reduce startup
@Configuration
public class BuildTimeInitializer {

    // These configurations are evaluated at build time
    // not at runtime
    static {
        // Initialize loggers at build time
        LoggerFactory.getLogger(BuildTimeInitializer.class);
    }

    @Bean
    @NativeHint(options = "--initialize-at-build-time=com.example.Constants")
    public ConstantsProvider constantsProvider() {
        // Constants are computed once at build
        return new ConstantsProvider();
    }
}

So sánh hiệu năng

Lợi ích về hiệu năng khi biên dịch native rất rõ ràng.

text
┌─────────────────────────────────────────────────────────────────────┐
│                    JIT vs Native Comparison                         │
├─────────────────────┬─────────────────┬─────────────────────────────┤
│ Metric              │ JIT (JVM)       │ Native (GraalVM)            │
├─────────────────────┼─────────────────┼─────────────────────────────┤
│ Startup time        │ 2.5 - 5 sec     │ 50 - 200 ms                 │
│ RSS Memory          │ 200 - 400 MB    │ 50 - 100 MB                 │
│ Executable size     │ JAR ~30 MB      │ Binary ~80 MB               │
│ First request time  │ 100 - 500 ms    │ < 10 ms                     │
│ Peak throughput     │ Excellent       │ Good (85-95% of JIT)        │
│ Build time          │ 30 sec          │ 3 - 10 min                  │
└─────────────────────┴─────────────────┴─────────────────────────────┘
Hiệu năng đỉnh

Thông lượng tối đa ở chế độ native có thể thấp hơn một chút so với chế độ JIT vì các tối ưu hóa thích nghi của JIT không khả dụng. Với các workload yêu cầu hiệu năng cao kéo dài, hãy đánh giá cả hai chế độ.

Khắc phục sự cố thường gặp

Lỗi reflection

Lỗi phổ biến nhất là reflection chưa được khai báo. Ngoại lệ chỉ ra lớp đang thiếu.

ReflectionErrorHandler.javajava
// Diagnosing and resolving reflection errors
@Component
@Slf4j
public class ReflectionErrorHandler {

    // Typical error:
    // java.lang.ClassNotFoundException: com.example.SomeClass
    // when accessing via reflection

    // Solution 1: Add manual configuration
    // src/main/resources/META-INF/native-image/reflect-config.json

    // Solution 2: Use @RegisterReflection annotation
    @RegisterReflection(classes = {
        SomeClass.class,
        AnotherClass.class
    })
    public void configureReflection() {
        // Annotated classes will be available for reflection
    }

    // Solution 3: Programmatic RuntimeHints
    public void registerHints(RuntimeHints hints) {
        hints.reflection().registerType(
            SomeClass.class,
            MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
            MemberCategory.INVOKE_DECLARED_METHODS
        );
    }
}

Tài nguyên bị thiếu

Các tệp tài nguyên phải được khai báo rõ ràng để được đưa vào native image.

src/main/resources/META-INF/native-image/resource-config.jsonjson
// Configuration for resources to include
{
  "resources": {
    "includes": [
      {"pattern": "application\\.yml"},
      {"pattern": "application-.*\\.yml"},
      {"pattern": "messages.*\\.properties"},
      {"pattern": "templates/.*\\.html"},
      {"pattern": "static/.*"},
      {"pattern": "db/migration/.*\\.sql"}
    ],
    "excludes": [
      {"pattern": ".*\\.java"},
      {"pattern": ".*\\.class"}
    ]
  },
  "bundles": [
    {"name": "messages"},
    {"name": "ValidationMessages"}
  ]
}
ResourceHintsConfig.javajava
// Programmatic resource configuration
@Configuration
@ImportRuntimeHints(ResourceHintsConfig.ResourceHints.class)
public class ResourceHintsConfig {

    static class ResourceHints implements RuntimeHintsRegistrar {

        @Override
        public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
            // YAML/Properties files
            hints.resources()
                .registerPattern("application*.yml")
                .registerPattern("application*.properties");

            // Thymeleaf templates
            hints.resources().registerPattern("templates/**");

            // Flyway SQL scripts
            hints.resources().registerPattern("db/migration/*.sql");

            // Static files
            hints.resources().registerPattern("static/**");

            // Message bundles
            hints.resources().registerResourceBundle("messages");
            hints.resources().registerResourceBundle("ValidationMessages");
        }
    }
}

Sự cố với proxy

Proxy JDK và CGLIB cần cấu hình riêng để hoạt động ở chế độ native.

ProxyConfiguration.javajava
// Managing proxies for native compilation
@Configuration
public class ProxyConfiguration implements RuntimeHintsRegistrar {

    @Override
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
        // JDK proxies for Spring Data interfaces
        hints.proxies().registerJdkProxy(
            UserRepository.class,
            Repository.class,
            CrudRepository.class
        );

        // Proxies for service interfaces
        hints.proxies().registerJdkProxy(
            PaymentService.class,
            TransactionalService.class
        );
    }

    // Alternative: force CGLIB proxies
    @Bean
    public BeanFactoryPostProcessor forceProxyTargetClass() {
        return beanFactory -> {
            // Use CGLIB instead of JDK proxies
            // More compatible with native compilation
        };
    }
}

Triển khai Docker và Kubernetes

Dockerfile multi-stage được tối ưu

Build multi-stage tách phần biên dịch và phần thực thi để có image nhỏ gọn nhất.

dockerfile
# Dockerfile
# Multi-stage build for Spring Boot Native

# Stage 1: Build with GraalVM
FROM ghcr.io/graalvm/graalvm-community:21 AS builder

# Install Native Image
RUN gu install native-image

WORKDIR /app

# Copy build files
COPY pom.xml .
COPY src ./src

# Install Maven
RUN microdnf install -y maven

# Native build with dependency caching
RUN --mount=type=cache,target=/root/.m2 \
    mvn -Pnative native:compile -DskipTests

# Stage 2: Minimal runtime image
FROM gcr.io/distroless/base-debian12

WORKDIR /app

# Copy native executable
COPY --from=builder /app/target/native-demo /app/native-demo

# Exposed port
EXPOSE 8080

# Healthcheck
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s \
    CMD ["/app/native-demo", "--health"]

# Execution
ENTRYPOINT ["/app/native-demo"]
dockerfile
# Dockerfile.alpine
# Alternative with Alpine for even smaller image
FROM ghcr.io/graalvm/native-image-community:21-muslib AS builder

WORKDIR /app
COPY pom.xml .
COPY src ./src

RUN --mount=type=cache,target=/root/.m2 \
    mvn -Pnative native:compile \
    -Dspring-boot.aot.jvmArguments="-Dspring.aot.processing.resource.matching.strategy=GLOB" \
    -DskipTests

# Minimal Alpine image (< 20 MB)
FROM alpine:3.19

RUN apk add --no-cache libc6-compat

WORKDIR /app
COPY --from=builder /app/target/native-demo /app/native-demo

EXPOSE 8080
ENTRYPOINT ["/app/native-demo"]

Triển khai Kubernetes với tài nguyên tối ưu

Ứng dụng native cần ít tài nguyên hơn ứng dụng JVM truyền thống.

yaml
# kubernetes/deployment.yaml
# Optimized Kubernetes deployment for native
apiVersion: apps/v1
kind: Deployment
metadata:
  name: native-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: native-demo
  template:
    metadata:
      labels:
        app: native-demo
    spec:
      containers:
        - name: native-demo
          image: registry.example.com/native-demo:1.0.0
          ports:
            - containerPort: 8080

          # Reduced resources thanks to native
          resources:
            requests:
              memory: "64Mi"    # vs 256Mi for JVM
              cpu: "50m"        # vs 200m for JVM
            limits:
              memory: "128Mi"   # vs 512Mi for JVM
              cpu: "200m"       # vs 500m for JVM

          # Fast probes (instant startup)
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 1    # vs 30s for JVM
            periodSeconds: 5
            failureThreshold: 3

          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 2    # vs 60s for JVM
            periodSeconds: 10
            failureThreshold: 3

          # Environment variables
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: "production"
            - name: JAVA_TOOL_OPTIONS
              value: ""  # No JVM options needed

---
apiVersion: v1
kind: Service
metadata:
  name: native-demo
spec:
  selector:
    app: native-demo
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: native-demo-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: native-demo
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
Mở rộng nhanh

Thời gian khởi động tức thì cho phép mở rộng theo chiều ngang rất nhanh. Pod mới sẵn sàng trong vài giây, lý tưởng cho các workload có lưu lượng đột biến.

Kiểm thử và xác minh native image

Cấu hình kiểm thử native

Các bài kiểm thử cũng có thể được biên dịch và chạy ở chế độ native để xác minh hành vi.

NativeIntegrationTest.javajava
// Integration tests for native validation
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
    "spring.datasource.url=jdbc:h2:mem:testdb",
    "spring.jpa.hibernate.ddl-auto=create-drop"
})
class NativeIntegrationTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldCreateAndRetrieveUser() {
        // Arrange: create a user
        UserDTO request = new UserDTO("John", "john@example.com");

        // Act: API call
        ResponseEntity<UserDTO> createResponse = restTemplate.postForEntity(
            "/api/users",
            request,
            UserDTO.class
        );

        // Assert: verify creation
        assertThat(createResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED);
        assertThat(createResponse.getBody()).isNotNull();
        assertThat(createResponse.getBody().getName()).isEqualTo("John");

        // Verify retrieval
        Long userId = createResponse.getBody().getId();
        ResponseEntity<UserDTO> getResponse = restTemplate.getForEntity(
            "/api/users/{id}",
            UserDTO.class,
            userId
        );

        assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(getResponse.getBody().getEmail()).isEqualTo("john@example.com");
    }

    @Test
    void shouldHandleReflectionCorrectly() {
        // Specific test to validate reflection configuration
        User user = new User();
        user.setName("Test");
        user.setEmail("test@example.com");

        // ORM uses reflection to map entities
        User saved = userRepository.save(user);

        assertThat(saved.getId()).isNotNull();
        assertThat(userRepository.findById(saved.getId())).isPresent();
    }
}
xml
<!-- pom.xml -->
<!-- Native tests configuration -->
<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
    <configuration>
        <testArgs>
            <!-- Include tests in native build -->
            <testArg>--verbose</testArg>
        </testArgs>
    </configuration>
    <executions>
        <execution>
            <id>test-native</id>
            <goals>
                <goal>test</goal>
            </goals>
            <phase>test</phase>
        </execution>
    </executions>
</plugin>

Sẵn sàng chinh phục phỏng vấn Spring Boot?

Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.

Kết luận

Biên dịch native với GraalVM biến ứng dụng Spring Boot 3 thành các tệp thực thi hiệu năng cao. Những điểm chính:

Cấu hình dự án:

  • ✅ Spring Boot 3.2+ với plugin GraalVM native
  • ✅ RuntimeHints cho reflection và tài nguyên
  • ✅ Tracing agent để phát hiện tự động

Tối ưu hóa build:

  • ✅ Tùy chọn biên dịch phù hợp (O2/O3, GC, nén)
  • ✅ Khởi tạo ngay tại build time cho các thành phần tĩnh
  • ✅ Quickbuild cho phát triển, build đầy đủ cho sản xuất

Khắc phục sự cố:

  • ✅ Cấu hình reflection rõ ràng cho thư viện bên thứ ba
  • ✅ Khai báo các tài nguyên cần đưa vào
  • ✅ Quản lý proxy JDK và CGLIB

Triển khai:

  • ✅ Image Docker multi-stage với distroless
  • ✅ Tài nguyên Kubernetes giảm (64 Mi so với 256 Mi)
  • ✅ Probes với độ trễ tối thiểu (khởi động tức thì)

Biên dịch native rất phù hợp cho microservices, hàm serverless và môi trường có tài nguyên hạn chế. Khởi động tức thì và mức tiêu thụ bộ nhớ thấp dư sức bù lại thời gian build dài hơn.

Bắt đầu luyện tập!

Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.

Thẻ

#graalvm
#spring boot 3
#native image
#aot compilation
#java performance

Chia sẻ

Bài viết liên quan