1. 创建第一个应用

1.1 项目结构

spring-native-demo/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           └── demo/
│   │   │               ├── Application.java
│   │   │               ├── config/
│   │   │               │   ├── WebConfig.java
│   │   │               │   └── NativeConfig.java
│   │   │               ├── controller/
│   │   │               │   ├── UserController.java
│   │   │               │   └── HealthController.java
│   │   │               ├── service/
│   │   │               │   ├── UserService.java
│   │   │               │   └── UserServiceImpl.java
│   │   │               ├── repository/
│   │   │               │   └── UserRepository.java
│   │   │               ├── model/
│   │   │               │   └── User.java
│   │   │               └── dto/
│   │   │                   ├── UserDto.java
│   │   │                   └── CreateUserRequest.java
│   │   └── resources/
│   │       ├── META-INF/
│   │       │   └── native-image/
│   │       │       ├── reflect-config.json
│   │       │       ├── resource-config.json
│   │       │       ├── serialization-config.json
│   │       │       └── proxy-config.json
│   │       ├── static/
│   │       │   └── index.html
│   │       └── application.yml
│   └── test/
│       └── java/
│           └── com/
│               └── example/
│                   └── demo/
│                       ├── ApplicationTests.java
│                       ├── controller/
│                       │   └── UserControllerTest.java
│                       └── service/
│                           └── UserServiceTest.java
├── pom.xml
└── README.md

1.2 主应用类

// src/main/java/com/example/demo/Application.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.nativex.hint.NativeHint;
import org.springframework.nativex.hint.TypeHint;
import org.springframework.nativex.hint.TypeAccess;
import org.springframework.nativex.hint.ResourceHint;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * Spring Native Demo 应用主类
 * 
 * 使用 @NativeHint 注解提供原生编译所需的配置信息
 */
@SpringBootApplication
@EnableJpaRepositories
@EnableTransactionManagement
@NativeHint(
    // 类型提示:指定需要反射访问的类
    types = {
        @TypeHint(
            types = {
                com.example.demo.model.User.class,
                com.example.demo.dto.UserDto.class,
                com.example.demo.dto.CreateUserRequest.class
            },
            access = {
                TypeAccess.DECLARED_CONSTRUCTORS,
                TypeAccess.DECLARED_METHODS,
                TypeAccess.DECLARED_FIELDS
            }
        ),
        // Jackson 序列化相关类
        @TypeHint(
            types = {
                com.fasterxml.jackson.databind.ObjectMapper.class,
                com.fasterxml.jackson.core.JsonGenerator.class,
                com.fasterxml.jackson.core.JsonParser.class
            },
            access = TypeAccess.DECLARED_CONSTRUCTORS
        ),
        // JPA 相关类
        @TypeHint(
            types = {
                org.hibernate.dialect.H2Dialect.class,
                org.h2.Driver.class
            },
            access = TypeAccess.DECLARED_CONSTRUCTORS
        )
    },
    // 资源提示:指定需要包含的资源文件
    resources = {
        @ResourceHint(patterns = {
            "application.yml",
            "application-*.yml",
            "static/**",
            "META-INF/spring.factories"
        })
    }
)
public class Application {
    
    public static void main(String[] args) {
        // 记录启动时间
        long startTime = System.currentTimeMillis();
        
        SpringApplication app = new SpringApplication(Application.class);
        
        // 设置应用属性
        app.setAdditionalProfiles("native");
        
        // 启动应用
        var context = app.run(args);
        
        long endTime = System.currentTimeMillis();
        System.out.printf("应用启动完成,耗时: %d ms%n", endTime - startTime);
        
        // 输出应用信息
        String port = context.getEnvironment().getProperty("server.port", "8080");
        System.out.printf("应用已启动,访问地址: http://localhost:%s%n", port);
        System.out.printf("健康检查: http://localhost:%s/actuator/health%n", port);
        System.out.printf("API 文档: http://localhost:%s/api/users%n", port);
    }
}

1.3 实体模型

// src/main/java/com/example/demo/model/User.java
package com.example.demo.model;

import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 用户实体类
 * 
 * 使用 JPA 注解进行数据库映射
 * 包含基本的用户信息和审计字段
 */
@Entity
@Table(name = "users", indexes = {
    @Index(name = "idx_user_email", columnList = "email", unique = true),
    @Index(name = "idx_user_username", columnList = "username", unique = true)
})
@EntityListeners(AuditingEntityListener.class)
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 50, message = "用户名长度必须在3-50个字符之间")
    @Column(name = "username", nullable = false, unique = true, length = 50)
    private String username;
    
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    @Column(name = "email", nullable = false, unique = true, length = 100)
    private String email;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, message = "密码长度至少6个字符")
    @Column(name = "password", nullable = false)
    private String password;
    
    @Size(max = 100, message = "姓名长度不能超过100个字符")
    @Column(name = "full_name", length = 100)
    private String fullName;
    
    @Min(value = 0, message = "年龄不能为负数")
    @Max(value = 150, message = "年龄不能超过150")
    @Column(name = "age")
    private Integer age;
    
    @Column(name = "active", nullable = false)
    private Boolean active = true;
    
    @CreatedDate
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;
    
    @LastModifiedDate
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;
    
    // 默认构造函数(JPA 需要)
    public User() {
    }
    
    // 构造函数
    public User(String username, String email, String password) {
        this.username = username;
        this.email = email;
        this.password = password;
    }
    
    public User(String username, String email, String password, String fullName, Integer age) {
        this(username, email, password);
        this.fullName = fullName;
        this.age = age;
    }
    
    // Getters and Setters
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    public String getFullName() {
        return fullName;
    }
    
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
    
    public Integer getAge() {
        return age;
    }
    
    public void setAge(Integer age) {
        this.age = age;
    }
    
    public Boolean getActive() {
        return active;
    }
    
    public void setActive(Boolean active) {
        this.active = active;
    }
    
    public LocalDateTime getCreatedAt() {
        return createdAt;
    }
    
    public void setCreatedAt(LocalDateTime createdAt) {
        this.createdAt = createdAt;
    }
    
    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }
    
    public void setUpdatedAt(LocalDateTime updatedAt) {
        this.updatedAt = updatedAt;
    }
    
    // 业务方法
    public void activate() {
        this.active = true;
    }
    
    public void deactivate() {
        this.active = false;
    }
    
    public boolean isActive() {
        return Boolean.TRUE.equals(this.active);
    }
    
    // equals, hashCode, toString
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) &&
               Objects.equals(username, user.username) &&
               Objects.equals(email, user.email);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id, username, email);
    }
    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", fullName='" + fullName + '\'' +
                ", age=" + age +
                ", active=" + active +
                ", createdAt=" + createdAt +
                ", updatedAt=" + updatedAt +
                '}';
    }
}

1.4 数据传输对象

// src/main/java/com/example/demo/dto/UserDto.java
package com.example.demo.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.validation.constraints.*;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 用户数据传输对象
 * 
 * 用于 API 响应,不包含敏感信息如密码
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserDto {
    
    private Long id;
    
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 50, message = "用户名长度必须在3-50个字符之间")
    private String username;
    
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @Size(max = 100, message = "姓名长度不能超过100个字符")
    private String fullName;
    
    @Min(value = 0, message = "年龄不能为负数")
    @Max(value = 150, message = "年龄不能超过150")
    private Integer age;
    
    private Boolean active;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createdAt;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updatedAt;
    
    // 默认构造函数
    public UserDto() {
    }
    
    // 构造函数
    public UserDto(Long id, String username, String email) {
        this.id = id;
        this.username = username;
        this.email = email;
    }
    
    public UserDto(Long id, String username, String email, String fullName, 
                   Integer age, Boolean active, LocalDateTime createdAt, LocalDateTime updatedAt) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.fullName = fullName;
        this.age = age;
        this.active = active;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
    }
    
    // Getters and Setters
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public String getFullName() {
        return fullName;
    }
    
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
    
    public Integer getAge() {
        return age;
    }
    
    public void setAge(Integer age) {
        this.age = age;
    }
    
    public Boolean getActive() {
        return active;
    }
    
    public void setActive(Boolean active) {
        this.active = active;
    }
    
    public LocalDateTime getCreatedAt() {
        return createdAt;
    }
    
    public void setCreatedAt(LocalDateTime createdAt) {
        this.createdAt = createdAt;
    }
    
    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }
    
    public void setUpdatedAt(LocalDateTime updatedAt) {
        this.updatedAt = updatedAt;
    }
    
    // equals, hashCode, toString
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserDto userDto = (UserDto) o;
        return Objects.equals(id, userDto.id) &&
               Objects.equals(username, userDto.username) &&
               Objects.equals(email, userDto.email);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id, username, email);
    }
    
    @Override
    public String toString() {
        return "UserDto{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", fullName='" + fullName + '\'' +
                ", age=" + age +
                ", active=" + active +
                ", createdAt=" + createdAt +
                ", updatedAt=" + updatedAt +
                '}';
    }
}
// src/main/java/com/example/demo/dto/CreateUserRequest.java
package com.example.demo.dto;

import jakarta.validation.constraints.*;

/**
 * 创建用户请求对象
 */
public class CreateUserRequest {
    
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 50, message = "用户名长度必须在3-50个字符之间")
    private String username;
    
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, message = "密码长度至少6个字符")
    private String password;
    
    @Size(max = 100, message = "姓名长度不能超过100个字符")
    private String fullName;
    
    @Min(value = 0, message = "年龄不能为负数")
    @Max(value = 150, message = "年龄不能超过150")
    private Integer age;
    
    // 默认构造函数
    public CreateUserRequest() {
    }
    
    // 构造函数
    public CreateUserRequest(String username, String email, String password) {
        this.username = username;
        this.email = email;
        this.password = password;
    }
    
    public CreateUserRequest(String username, String email, String password, 
                           String fullName, Integer age) {
        this(username, email, password);
        this.fullName = fullName;
        this.age = age;
    }
    
    // Getters and Setters
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    public String getFullName() {
        return fullName;
    }
    
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
    
    public Integer getAge() {
        return age;
    }
    
    public void setAge(Integer age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "CreateUserRequest{" +
                "username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", fullName='" + fullName + '\'' +
                ", age=" + age +
                '}';
    }
}

1.5 数据访问层

// src/main/java/com/example/demo/repository/UserRepository.java
package com.example.demo.repository;

import com.example.demo.model.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 用户数据访问接口
 * 
 * 继承 JpaRepository 提供基本的 CRUD 操作
 * 定义自定义查询方法
 */
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    /**
     * 根据用户名查找用户
     */
    Optional<User> findByUsername(String username);
    
    /**
     * 根据邮箱查找用户
     */
    Optional<User> findByEmail(String email);
    
    /**
     * 检查用户名是否存在
     */
    boolean existsByUsername(String username);
    
    /**
     * 检查邮箱是否存在
     */
    boolean existsByEmail(String email);
    
    /**
     * 根据激活状态查找用户
     */
    List<User> findByActive(Boolean active);
    
    /**
     * 根据激活状态分页查找用户
     */
    Page<User> findByActive(Boolean active, Pageable pageable);
    
    /**
     * 根据年龄范围查找用户
     */
    List<User> findByAgeBetween(Integer minAge, Integer maxAge);
    
    /**
     * 根据用户名模糊查找(忽略大小写)
     */
    List<User> findByUsernameContainingIgnoreCase(String username);
    
    /**
     * 根据邮箱域名查找用户
     */
    @Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
    List<User> findByEmailDomain(@Param("domain") String domain);
    
    /**
     * 查找指定时间之后创建的用户
     */
    @Query("SELECT u FROM User u WHERE u.createdAt >= :date")
    List<User> findUsersCreatedAfter(@Param("date") LocalDateTime date);
    
    /**
     * 统计激活用户数量
     */
    @Query("SELECT COUNT(u) FROM User u WHERE u.active = true")
    long countActiveUsers();
    
    /**
     * 查找最近注册的用户
     */
    @Query("SELECT u FROM User u ORDER BY u.createdAt DESC")
    List<User> findRecentUsers(Pageable pageable);
    
    /**
     * 根据多个条件查找用户
     */
    @Query("SELECT u FROM User u WHERE " +
           "(:username IS NULL OR u.username LIKE %:username%) AND " +
           "(:email IS NULL OR u.email LIKE %:email%) AND " +
           "(:active IS NULL OR u.active = :active) AND " +
           "(:minAge IS NULL OR u.age >= :minAge) AND " +
           "(:maxAge IS NULL OR u.age <= :maxAge)")
    Page<User> findUsersByCriteria(
        @Param("username") String username,
        @Param("email") String email,
        @Param("active") Boolean active,
        @Param("minAge") Integer minAge,
        @Param("maxAge") Integer maxAge,
        Pageable pageable
    );
}

1.6 服务层

// src/main/java/com/example/demo/service/UserService.java
package com.example.demo.service;

import com.example.demo.dto.CreateUserRequest;
import com.example.demo.dto.UserDto;
import com.example.demo.model.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 用户服务接口
 * 
 * 定义用户相关的业务操作
 */
public interface UserService {
    
    /**
     * 创建用户
     */
    UserDto createUser(CreateUserRequest request);
    
    /**
     * 根据 ID 查找用户
     */
    Optional<UserDto> findById(Long id);
    
    /**
     * 根据用户名查找用户
     */
    Optional<UserDto> findByUsername(String username);
    
    /**
     * 根据邮箱查找用户
     */
    Optional<UserDto> findByEmail(String email);
    
    /**
     * 获取所有用户
     */
    List<UserDto> findAll();
    
    /**
     * 分页获取用户
     */
    Page<UserDto> findAll(Pageable pageable);
    
    /**
     * 根据激活状态获取用户
     */
    List<UserDto> findByActive(Boolean active);
    
    /**
     * 根据激活状态分页获取用户
     */
    Page<UserDto> findByActive(Boolean active, Pageable pageable);
    
    /**
     * 更新用户信息
     */
    UserDto updateUser(Long id, UserDto userDto);
    
    /**
     * 激活用户
     */
    void activateUser(Long id);
    
    /**
     * 停用用户
     */
    void deactivateUser(Long id);
    
    /**
     * 删除用户
     */
    void deleteUser(Long id);
    
    /**
     * 检查用户名是否存在
     */
    boolean existsByUsername(String username);
    
    /**
     * 检查邮箱是否存在
     */
    boolean existsByEmail(String email);
    
    /**
     * 根据年龄范围查找用户
     */
    List<UserDto> findByAgeRange(Integer minAge, Integer maxAge);
    
    /**
     * 搜索用户
     */
    List<UserDto> searchUsers(String keyword);
    
    /**
     * 根据条件查找用户
     */
    Page<UserDto> findUsersByCriteria(String username, String email, Boolean active, 
                                     Integer minAge, Integer maxAge, Pageable pageable);
    
    /**
     * 获取用户统计信息
     */
    UserStatistics getUserStatistics();
    
    /**
     * 用户统计信息内部类
     */
    class UserStatistics {
        private final long totalUsers;
        private final long activeUsers;
        private final long inactiveUsers;
        private final LocalDateTime lastRegistration;
        
        public UserStatistics(long totalUsers, long activeUsers, long inactiveUsers, LocalDateTime lastRegistration) {
            this.totalUsers = totalUsers;
            this.activeUsers = activeUsers;
            this.inactiveUsers = inactiveUsers;
            this.lastRegistration = lastRegistration;
        }
        
        public long getTotalUsers() { return totalUsers; }
        public long getActiveUsers() { return activeUsers; }
        public long getInactiveUsers() { return inactiveUsers; }
        public LocalDateTime getLastRegistration() { return lastRegistration; }
        
        @Override
        public String toString() {
            return "UserStatistics{" +
                    "totalUsers=" + totalUsers +
                    ", activeUsers=" + activeUsers +
                    ", inactiveUsers=" + inactiveUsers +
                    ", lastRegistration=" + lastRegistration +
                    '}';
        }
    }
}
// src/main/java/com/example/demo/service/UserServiceImpl.java
package com.example.demo.service;

import com.example.demo.dto.CreateUserRequest;
import com.example.demo.dto.UserDto;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 * 
 * 实现用户相关的业务逻辑
 */
@Service
@Transactional
public class UserServiceImpl implements UserService {
    
    private final UserRepository userRepository;
    
    @Autowired
    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @Override
    public UserDto createUser(CreateUserRequest request) {
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new IllegalArgumentException("用户名已存在: " + request.getUsername());
        }
        
        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new IllegalArgumentException("邮箱已存在: " + request.getEmail());
        }
        
        // 创建用户实体
        User user = new User(
            request.getUsername(),
            request.getEmail(),
            request.getPassword(),
            request.getFullName(),
            request.getAge()
        );
        
        // 保存用户
        User savedUser = userRepository.save(user);
        
        // 转换为 DTO 并返回
        return convertToDto(savedUser);
    }
    
    @Override
    @Transactional(readOnly = true)
    public Optional<UserDto> findById(Long id) {
        return userRepository.findById(id)
                .map(this::convertToDto);
    }
    
    @Override
    @Transactional(readOnly = true)
    public Optional<UserDto> findByUsername(String username) {
        return userRepository.findByUsername(username)
                .map(this::convertToDto);
    }
    
    @Override
    @Transactional(readOnly = true)
    public Optional<UserDto> findByEmail(String email) {
        return userRepository.findByEmail(email)
                .map(this::convertToDto);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<UserDto> findAll() {
        return userRepository.findAll().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<UserDto> findAll(Pageable pageable) {
        return userRepository.findAll(pageable)
                .map(this::convertToDto);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<UserDto> findByActive(Boolean active) {
        return userRepository.findByActive(active).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<UserDto> findByActive(Boolean active, Pageable pageable) {
        return userRepository.findByActive(active, pageable)
                .map(this::convertToDto);
    }
    
    @Override
    public UserDto updateUser(Long id, UserDto userDto) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("用户不存在: " + id));
        
        // 更新用户信息
        if (userDto.getUsername() != null && !userDto.getUsername().equals(user.getUsername())) {
            if (userRepository.existsByUsername(userDto.getUsername())) {
                throw new IllegalArgumentException("用户名已存在: " + userDto.getUsername());
            }
            user.setUsername(userDto.getUsername());
        }
        
        if (userDto.getEmail() != null && !userDto.getEmail().equals(user.getEmail())) {
            if (userRepository.existsByEmail(userDto.getEmail())) {
                throw new IllegalArgumentException("邮箱已存在: " + userDto.getEmail());
            }
            user.setEmail(userDto.getEmail());
        }
        
        if (userDto.getFullName() != null) {
            user.setFullName(userDto.getFullName());
        }
        
        if (userDto.getAge() != null) {
            user.setAge(userDto.getAge());
        }
        
        if (userDto.getActive() != null) {
            user.setActive(userDto.getActive());
        }
        
        User updatedUser = userRepository.save(user);
        return convertToDto(updatedUser);
    }
    
    @Override
    public void activateUser(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("用户不存在: " + id));
        user.activate();
        userRepository.save(user);
    }
    
    @Override
    public void deactivateUser(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("用户不存在: " + id));
        user.deactivate();
        userRepository.save(user);
    }
    
    @Override
    public void deleteUser(Long id) {
        if (!userRepository.existsById(id)) {
            throw new IllegalArgumentException("用户不存在: " + id);
        }
        userRepository.deleteById(id);
    }
    
    @Override
    @Transactional(readOnly = true)
    public boolean existsByUsername(String username) {
        return userRepository.existsByUsername(username);
    }
    
    @Override
    @Transactional(readOnly = true)
    public boolean existsByEmail(String email) {
        return userRepository.existsByEmail(email);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<UserDto> findByAgeRange(Integer minAge, Integer maxAge) {
        return userRepository.findByAgeBetween(minAge, maxAge).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<UserDto> searchUsers(String keyword) {
        return userRepository.findByUsernameContainingIgnoreCase(keyword).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<UserDto> findUsersByCriteria(String username, String email, Boolean active,
                                           Integer minAge, Integer maxAge, Pageable pageable) {
        return userRepository.findUsersByCriteria(username, email, active, minAge, maxAge, pageable)
                .map(this::convertToDto);
    }
    
    @Override
    @Transactional(readOnly = true)
    public UserStatistics getUserStatistics() {
        long totalUsers = userRepository.count();
        long activeUsers = userRepository.countActiveUsers();
        long inactiveUsers = totalUsers - activeUsers;
        
        LocalDateTime lastRegistration = null;
        List<User> recentUsers = userRepository.findRecentUsers(PageRequest.of(0, 1));
        if (!recentUsers.isEmpty()) {
            lastRegistration = recentUsers.get(0).getCreatedAt();
        }
        
        return new UserStatistics(totalUsers, activeUsers, inactiveUsers, lastRegistration);
    }
    
    /**
     * 将 User 实体转换为 UserDto
     */
    private UserDto convertToDto(User user) {
        return new UserDto(
            user.getId(),
            user.getUsername(),
            user.getEmail(),
            user.getFullName(),
            user.getAge(),
            user.getActive(),
            user.getCreatedAt(),
            user.getUpdatedAt()
        );
    }
}

2. 控制器层

2.1 用户控制器

// src/main/java/com/example/demo/controller/UserController.java
package com.example.demo.controller;

import com.example.demo.dto.CreateUserRequest;
import com.example.demo.dto.UserDto;
import com.example.demo.service.UserService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 用户控制器
 * 
 * 提供用户相关的 REST API 接口
 */
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
    
    private final UserService userService;
    
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    /**
     * 创建用户
     */
    @PostMapping
    public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
        try {
            UserDto user = userService.createUser(request);
            return ResponseEntity.status(HttpStatus.CREATED).body(user);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().build();
        }
    }
    
    /**
     * 根据 ID 获取用户
     */
    @GetMapping("/{id}")
    public ResponseEntity<UserDto> getUserById(@PathVariable @Min(1) Long id) {
        Optional<UserDto> user = userService.findById(id);
        return user.map(ResponseEntity::ok)
                  .orElse(ResponseEntity.notFound().build());
    }
    
    /**
     * 获取所有用户(分页)
     */
    @GetMapping
    public ResponseEntity<Page<UserDto>> getAllUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "id") String sortBy,
            @RequestParam(defaultValue = "asc") String sortDir) {
        
        Sort sort = sortDir.equalsIgnoreCase("desc") 
            ? Sort.by(sortBy).descending() 
            : Sort.by(sortBy).ascending();
        
        Pageable pageable = PageRequest.of(page, size, sort);
        Page<UserDto> users = userService.findAll(pageable);
        
        return ResponseEntity.ok(users);
    }
    
    /**
     * 根据激活状态获取用户
     */
    @GetMapping("/active/{active}")
    public ResponseEntity<List<UserDto>> getUsersByActive(@PathVariable Boolean active) {
        List<UserDto> users = userService.findByActive(active);
        return ResponseEntity.ok(users);
    }
    
    /**
     * 搜索用户
     */
    @GetMapping("/search")
    public ResponseEntity<Page<UserDto>> searchUsers(
            @RequestParam(required = false) String username,
            @RequestParam(required = false) String email,
            @RequestParam(required = false) Boolean active,
            @RequestParam(required = false) Integer minAge,
            @RequestParam(required = false) Integer maxAge,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "id") String sortBy,
            @RequestParam(defaultValue = "asc") String sortDir) {
        
        Sort sort = sortDir.equalsIgnoreCase("desc") 
            ? Sort.by(sortBy).descending() 
            : Sort.by(sortBy).ascending();
        
        Pageable pageable = PageRequest.of(page, size, sort);
        Page<UserDto> users = userService.findUsersByCriteria(
            username, email, active, minAge, maxAge, pageable);
        
        return ResponseEntity.ok(users);
    }
    
    /**
     * 根据关键词搜索用户
     */
    @GetMapping("/search/{keyword}")
    public ResponseEntity<List<UserDto>> searchUsersByKeyword(@PathVariable String keyword) {
        List<UserDto> users = userService.searchUsers(keyword);
        return ResponseEntity.ok(users);
    }
    
    /**
     * 更新用户信息
     */
    @PutMapping("/{id}")
    public ResponseEntity<UserDto> updateUser(
            @PathVariable @Min(1) Long id,
            @Valid @RequestBody UserDto userDto) {
        try {
            UserDto updatedUser = userService.updateUser(id, userDto);
            return ResponseEntity.ok(updatedUser);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().build();
        }
    }
    
    /**
     * 激活用户
     */
    @PatchMapping("/{id}/activate")
    public ResponseEntity<Void> activateUser(@PathVariable @Min(1) Long id) {
        try {
            userService.activateUser(id);
            return ResponseEntity.ok().build();
        } catch (IllegalArgumentException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    /**
     * 停用用户
     */
    @PatchMapping("/{id}/deactivate")
    public ResponseEntity<Void> deactivateUser(@PathVariable @Min(1) Long id) {
        try {
            userService.deactivateUser(id);
            return ResponseEntity.ok().build();
        } catch (IllegalArgumentException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    /**
     * 删除用户
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable @Min(1) Long id) {
        try {
            userService.deleteUser(id);
            return ResponseEntity.noContent().build();
        } catch (IllegalArgumentException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    /**
     * 检查用户名是否存在
     */
    @GetMapping("/check/username/{username}")
    public ResponseEntity<Map<String, Boolean>> checkUsername(@PathVariable String username) {
        boolean exists = userService.existsByUsername(username);
        return ResponseEntity.ok(Map.of("exists", exists));
    }
    
    /**
     * 检查邮箱是否存在
     */
    @GetMapping("/check/email/{email}")
    public ResponseEntity<Map<String, Boolean>> checkEmail(@PathVariable String email) {
        boolean exists = userService.existsByEmail(email);
        return ResponseEntity.ok(Map.of("exists", exists));
    }
    
    /**
     * 获取用户统计信息
     */
    @GetMapping("/statistics")
    public ResponseEntity<UserService.UserStatistics> getUserStatistics() {
        UserService.UserStatistics statistics = userService.getUserStatistics();
        return ResponseEntity.ok(statistics);
    }
    
    /**
     * 根据年龄范围获取用户
     */
    @GetMapping("/age-range")
    public ResponseEntity<List<UserDto>> getUsersByAgeRange(
            @RequestParam Integer minAge,
            @RequestParam Integer maxAge) {
        List<UserDto> users = userService.findByAgeRange(minAge, maxAge);
        return ResponseEntity.ok(users);
    }
}

2.2 健康检查控制器

// src/main/java/com/example/demo/controller/HealthController.java
package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuator.health.Health;
import org.springframework.boot.actuator.health.HealthIndicator;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;
import java.sql.Connection;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 健康检查控制器
 * 
 * 提供应用健康状态检查接口
 */
@RestController
@RequestMapping("/api/health")
public class HealthController implements HealthIndicator {
    
    @Autowired
    private DataSource dataSource;
    
    /**
     * 基本健康检查
     */
    @GetMapping
    public ResponseEntity<Map<String, Object>> health() {
        Map<String, Object> health = new HashMap<>();
        health.put("status", "UP");
        health.put("timestamp", LocalDateTime.now());
        health.put("application", "Spring Native Demo");
        health.put("version", "1.0.0");
        
        return ResponseEntity.ok(health);
    }
    
    /**
     * 详细健康检查
     */
    @GetMapping("/detailed")
    public ResponseEntity<Map<String, Object>> detailedHealth() {
        Map<String, Object> health = new HashMap<>();
        
        // 基本信息
        health.put("status", "UP");
        health.put("timestamp", LocalDateTime.now());
        health.put("application", "Spring Native Demo");
        health.put("version", "1.0.0");
        
        // 系统信息
        Map<String, Object> system = new HashMap<>();
        Runtime runtime = Runtime.getRuntime();
        system.put("processors", runtime.availableProcessors());
        system.put("totalMemory", runtime.totalMemory());
        system.put("freeMemory", runtime.freeMemory());
        system.put("maxMemory", runtime.maxMemory());
        system.put("usedMemory", runtime.totalMemory() - runtime.freeMemory());
        health.put("system", system);
        
        // 数据库连接检查
        Map<String, Object> database = new HashMap<>();
        try (Connection connection = dataSource.getConnection()) {
            database.put("status", "UP");
            database.put("url", connection.getMetaData().getURL());
            database.put("driver", connection.getMetaData().getDriverName());
            database.put("version", connection.getMetaData().getDriverVersion());
        } catch (Exception e) {
            database.put("status", "DOWN");
            database.put("error", e.getMessage());
        }
        health.put("database", database);
        
        return ResponseEntity.ok(health);
    }
    
    /**
     * Spring Boot Actuator 健康指示器
     */
    @Override
    public Health health() {
        try (Connection connection = dataSource.getConnection()) {
            return Health.up()
                    .withDetail("database", "Available")
                    .withDetail("timestamp", LocalDateTime.now())
                    .build();
        } catch (Exception e) {
            return Health.down()
                    .withDetail("database", "Unavailable")
                    .withDetail("error", e.getMessage())
                    .withDetail("timestamp", LocalDateTime.now())
                    .build();
        }
    }
    
    /**
     * 就绪检查
     */
    @GetMapping("/ready")
    public ResponseEntity<Map<String, Object>> ready() {
        Map<String, Object> readiness = new HashMap<>();
        
        boolean isReady = true;
        StringBuilder message = new StringBuilder();
        
        // 检查数据库连接
        try (Connection connection = dataSource.getConnection()) {
            message.append("Database: OK; ");
        } catch (Exception e) {
            isReady = false;
            message.append("Database: FAIL - ").append(e.getMessage()).append("; ");
        }
        
        readiness.put("ready", isReady);
        readiness.put("status", isReady ? "READY" : "NOT_READY");
        readiness.put("message", message.toString());
        readiness.put("timestamp", LocalDateTime.now());
        
        return ResponseEntity.ok(readiness);
    }
    
    /**
     * 存活检查
     */
    @GetMapping("/live")
    public ResponseEntity<Map<String, Object>> live() {
        Map<String, Object> liveness = new HashMap<>();
        liveness.put("alive", true);
        liveness.put("status", "ALIVE");
        liveness.put("timestamp", LocalDateTime.now());
        liveness.put("uptime", System.currentTimeMillis());
        
        return ResponseEntity.ok(liveness);
    }
}

3. 配置类

3.1 Web 配置

// src/main/java/com/example/demo/config/WebConfig.java
package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * Web 配置类
 * 
 * 配置 Web 相关设置,如 CORS、拦截器等
 */
@Configuration
@EnableJpaAuditing
public class WebConfig implements WebMvcConfigurer {
    
    /**
     * 配置 CORS
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://localhost:3000", "http://localhost:8080")
                .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

3.2 原生配置

// src/main/java/com/example/demo/config/NativeConfig.java
package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.nativex.hint.NativeHint;
import org.springframework.nativex.hint.TypeHint;
import org.springframework.nativex.hint.TypeAccess;
import org.springframework.nativex.hint.ResourceHint;
import org.springframework.nativex.hint.JniHint;

/**
 * 原生镜像配置类
 * 
 * 提供原生编译所需的额外配置信息
 */
@Configuration
@NativeHint(
    // 反射类型配置
    types = {
        // H2 数据库相关
        @TypeHint(
            types = {
                org.h2.Driver.class,
                org.h2.engine.Engine.class,
                org.h2.store.fs.FilePathDisk.class
            },
            access = {
                TypeAccess.DECLARED_CONSTRUCTORS,
                TypeAccess.DECLARED_METHODS
            }
        ),
        // Hibernate 相关
        @TypeHint(
            types = {
                org.hibernate.dialect.H2Dialect.class,
                org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl.class,
                org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl.class
            },
            access = TypeAccess.DECLARED_CONSTRUCTORS
        ),
        // Jackson 相关
        @TypeHint(
            types = {
                com.fasterxml.jackson.databind.ser.std.StringSerializer.class,
                com.fasterxml.jackson.databind.ser.std.NumberSerializers.LongSerializer.class,
                com.fasterxml.jackson.databind.ser.std.NumberSerializers.IntegerSerializer.class,
                com.fasterxml.jackson.databind.ser.std.BooleanSerializer.class,
                com.fasterxml.jackson.databind.deser.std.StringDeserializer.class,
                com.fasterxml.jackson.databind.deser.std.NumberDeserializers.LongDeserializer.class,
                com.fasterxml.jackson.databind.deser.std.NumberDeserializers.IntegerDeserializer.class,
                com.fasterxml.jackson.databind.deser.std.NumberDeserializers.BooleanDeserializer.class
            },
            access = TypeAccess.DECLARED_CONSTRUCTORS
        ),
        // 应用实体类
        @TypeHint(
            types = {
                com.example.demo.model.User.class,
                com.example.demo.dto.UserDto.class,
                com.example.demo.dto.CreateUserRequest.class
            },
            access = {
                TypeAccess.DECLARED_CONSTRUCTORS,
                TypeAccess.DECLARED_METHODS,
                TypeAccess.DECLARED_FIELDS,
                TypeAccess.PUBLIC_METHODS
            }
        )
    },
    // 资源配置
    resources = {
        @ResourceHint(patterns = {
            "application*.yml",
            "application*.yaml",
            "application*.properties",
            "META-INF/spring.factories",
            "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
            "org/hibernate/validator/ValidationMessages.properties",
            "ValidationMessages.properties"
        })
    }
)
public class NativeConfig {
    // 配置类主体为空,所有配置通过注解提供
}

4. 静态资源

4.1 首页

<!-- src/main/resources/static/index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spring Native Demo</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            color: #333;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: rgba(255, 255, 255, 0.95);
            border-radius: 15px;
            padding: 40px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
        }
        h1 {
            text-align: center;
            color: #4a5568;
            margin-bottom: 40px;
            font-size: 2.5em;
            font-weight: 300;
        }
        .status-card {
            background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);
            color: white;
            padding: 20px;
            border-radius: 10px;
            text-align: center;
            margin-bottom: 30px;
            box-shadow: 0 10px 20px rgba(72, 187, 120, 0.3);
        }
        .api-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
            gap: 25px;
            margin-bottom: 30px;
        }
        .api-section {
            background: #f7fafc;
            border: 1px solid #e2e8f0;
            border-radius: 10px;
            padding: 25px;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        .api-section:hover {
            transform: translateY(-5px);
            box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
        }
        .api-title {
            font-size: 1.3em;
            font-weight: 600;
            color: #2d3748;
            margin-bottom: 15px;
            border-bottom: 2px solid #667eea;
            padding-bottom: 10px;
        }
        .endpoint {
            background: #edf2f7;
            border-left: 4px solid #667eea;
            padding: 12px 15px;
            margin: 10px 0;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            font-size: 0.9em;
            transition: background 0.2s;
        }
        .endpoint:hover {
            background: #e2e8f0;
        }
        .method {
            font-weight: bold;
            color: #667eea;
        }
        .footer {
            text-align: center;
            margin-top: 40px;
            padding-top: 20px;
            border-top: 1px solid #e2e8f0;
            color: #718096;
        }
        .build-info {
            background: #f0fff4;
            border: 1px solid #9ae6b4;
            border-radius: 8px;
            padding: 15px;
            margin-top: 20px;
        }
        @media (max-width: 768px) {
            .container {
                padding: 20px;
            }
            .api-grid {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🚀 Spring Native Demo Application</h1>
        
        <div class="status-card">
            <h2>✅ 应用运行状态</h2>
            <p id="status-text">应用正常运行中</p>
            <p>启动模式: <span id="runtime-mode">检测中...</span></p>
        </div>
        
        <div class="api-grid">
            <div class="api-section">
                <div class="api-title">👥 用户管理 API</div>
                <div class="endpoint">
                    <span class="method">GET</span> /api/users - 获取所有用户
                </div>
                <div class="endpoint">
                    <span class="method">GET</span> /api/users/{id} - 获取指定用户
                </div>
                <div class="endpoint">
                    <span class="method">POST</span> /api/users - 创建新用户
                </div>
                <div class="endpoint">
                    <span class="method">PUT</span> /api/users/{id} - 更新用户信息
                </div>
                <div class="endpoint">
                    <span class="method">DELETE</span> /api/users/{id} - 删除用户
                </div>
            </div>
            
            <div class="api-section">
                <div class="api-title">🏥 健康检查</div>
                <div class="endpoint">
                    <span class="method">GET</span> /health - 基础健康状态
                </div>
                <div class="endpoint">
                    <span class="method">GET</span> /health/detailed - 详细健康信息
                </div>
            </div>
            
            <div class="api-section">
                <div class="api-title">📊 统计信息</div>
                <div class="endpoint">
                    <span class="method">GET</span> /api/users/stats - 用户统计数据
                </div>
            </div>
            
            <div class="api-section">
                <div class="api-title">🔧 系统信息</div>
                <div class="endpoint">
                    <span class="method">GET</span> /actuator/info - 应用信息
                </div>
                <div class="endpoint">
                    <span class="method">GET</span> /actuator/metrics - 性能指标
                </div>
            </div>
        </div>
        
        <div class="footer">
            <h3>Spring Native Demo</h3>
            <p>原生镜像应用示例 - 展示 Spring Native 的强大性能</p>
            <div class="build-info">
                <strong>构建信息:</strong><br>
                构建时间: <span id="build-time"></span><br>
                运行时间: <span id="uptime"></span>
            </div>
        </div>
    </div>
    
    <script>
        // 页面加载时初始化
        document.addEventListener('DOMContentLoaded', function() {
            updateBuildTime();
            checkApplicationHealth();
            detectRuntimeMode();
            startUptimeCounter();
        });
        
        // 更新构建时间
        function updateBuildTime() {
            document.getElementById('build-time').textContent = new Date().toLocaleString('zh-CN');
        }
        
        // 检查应用健康状态
        async function checkApplicationHealth() {
            try {
                const response = await fetch('/health');
                const statusText = document.getElementById('status-text');
                
                if (response.ok) {
                    statusText.textContent = '✅ 应用健康运行中';
                    statusText.style.color = '#48bb78';
                } else {
                    statusText.textContent = '⚠️ 应用状态异常';
                    statusText.style.color = '#f56565';
                }
            } catch (error) {
                document.getElementById('status-text').textContent = '❌ 无法连接到应用';
                console.error('健康检查失败:', error);
            }
        }
        
        // 检测运行时模式
        async function detectRuntimeMode() {
            try {
                const response = await fetch('/health/detailed');
                if (response.ok) {
                    const data = await response.json();
                    const mode = data.nativeImage ? 'Native Image' : 'JVM';
                    document.getElementById('runtime-mode').textContent = mode;
                }
            } catch (error) {
                document.getElementById('runtime-mode').textContent = '未知';
            }
        }
        
        // 启动运行时间计数器
        function startUptimeCounter() {
            const startTime = Date.now();
            
            setInterval(() => {
                const uptime = Date.now() - startTime;
                const seconds = Math.floor(uptime / 1000) % 60;
                const minutes = Math.floor(uptime / (1000 * 60)) % 60;
                const hours = Math.floor(uptime / (1000 * 60 * 60));
                
                document.getElementById('uptime').textContent = 
                    `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
            }, 1000);
        }
        
        // 定期健康检查
        setInterval(checkApplicationHealth, 30000); // 每30秒检查一次
    </script>
</body>
</html>

5. 构建与运行

5.1 传统 JVM 模式运行

# 编译项目
mvn clean compile

# 运行应用
mvn spring-boot:run

# 或者打包后运行
mvn clean package
java -jar target/spring-native-demo-1.0.0.jar

5.2 原生镜像构建

# 构建原生镜像(需要 GraalVM)
mvn clean -Pnative native:compile

# 运行原生镜像
./target/spring-native-demo

# Windows 环境
.\target\spring-native-demo.exe

5.3 Docker 构建

# Dockerfile.native
FROM ghcr.io/graalvm/graalvm-ce:ol8-java17-22.3.0 AS builder

WORKDIR /app
COPY . .

# 安装 Maven
RUN microdnf install -y wget tar gzip && \
    wget https://archive.apache.org/dist/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz && \
    tar -xzf apache-maven-3.8.6-bin.tar.gz && \
    mv apache-maven-3.8.6 /opt/maven && \
    ln -s /opt/maven/bin/mvn /usr/local/bin/mvn

# 构建原生镜像
RUN mvn clean -Pnative native:compile

# 运行时镜像
FROM oraclelinux:8-slim
WORKDIR /app
COPY --from=builder /app/target/spring-native-demo ./app
EXPOSE 8080
CMD ["./app"]
# 构建 Docker 镜像
docker build -f Dockerfile.native -t spring-native-demo:native .

# 运行容器
docker run -p 8080:8080 spring-native-demo:native

6. 性能对比测试

6.1 启动时间测试

#!/bin/bash
# startup-test.sh

echo "=== Spring Native 启动时间测试 ==="

# JVM 模式测试
echo "测试 JVM 模式启动时间..."
JVM_START=$(date +%s%N)
java -jar target/spring-native-demo-1.0.0.jar &
JVM_PID=$!

# 等待应用启动
while ! curl -s http://localhost:8080/health > /dev/null; do
    sleep 0.1
done

JVM_END=$(date +%s%N)
JVM_TIME=$(((JVM_END - JVM_START) / 1000000))
echo "JVM 模式启动时间: ${JVM_TIME}ms"

# 停止 JVM 应用
kill $JVM_PID
sleep 2

# 原生镜像测试
echo "测试原生镜像启动时间..."
NATIVE_START=$(date +%s%N)
./target/spring-native-demo &
NATIVE_PID=$!

# 等待应用启动
while ! curl -s http://localhost:8080/health > /dev/null; do
    sleep 0.1
done

NATIVE_END=$(date +%s%N)
NATIVE_TIME=$(((NATIVE_END - NATIVE_START) / 1000000))
echo "原生镜像启动时间: ${NATIVE_TIME}ms"

# 计算性能提升
IMPROVEMENT=$((JVM_TIME / NATIVE_TIME))
echo "性能提升: ${IMPROVEMENT}x"

# 停止原生应用
kill $NATIVE_PID

6.2 内存使用测试

#!/bin/bash
# memory-test.sh

echo "=== Spring Native 内存使用测试 ==="

# JVM 模式内存测试
echo "启动 JVM 模式应用..."
java -jar target/spring-native-demo-1.0.0.jar &
JVM_PID=$!
sleep 10

JVM_MEMORY=$(ps -o rss= -p $JVM_PID)
echo "JVM 模式内存使用: ${JVM_MEMORY}KB"
kill $JVM_PID
sleep 2

# 原生镜像内存测试
echo "启动原生镜像应用..."
./target/spring-native-demo &
NATIVE_PID=$!
sleep 10

NATIVE_MEMORY=$(ps -o rss= -p $NATIVE_PID)
echo "原生镜像内存使用: ${NATIVE_MEMORY}KB"

# 计算内存节省
MEMORY_SAVING=$(((JVM_MEMORY - NATIVE_MEMORY) * 100 / JVM_MEMORY))
echo "内存节省: ${MEMORY_SAVING}%"

kill $NATIVE_PID

7. 测试验证

7.1 API 功能测试

#!/bin/bash
# api-test.sh

BASE_URL="http://localhost:8080"

echo "=== Spring Native API 功能测试 ==="

# 健康检查
echo "1. 健康检查测试"
curl -s "$BASE_URL/health" | jq .

# 创建用户
echo "2. 创建用户测试"
USER_DATA='{"name":"张三","email":"zhangsan@example.com","age":25}'
USER_ID=$(curl -s -X POST "$BASE_URL/api/users" \
    -H "Content-Type: application/json" \
    -d "$USER_DATA" | jq -r '.id')
echo "创建用户 ID: $USER_ID"

# 查询用户
echo "3. 查询用户测试"
curl -s "$BASE_URL/api/users/$USER_ID" | jq .

# 更新用户
echo "4. 更新用户测试"
UPDATE_DATA='{"name":"张三丰","email":"zhangsanfeng@example.com","age":30}'
curl -s -X PUT "$BASE_URL/api/users/$USER_ID" \
    -H "Content-Type: application/json" \
    -d "$UPDATE_DATA" | jq .

# 获取所有用户
echo "5. 获取所有用户测试"
curl -s "$BASE_URL/api/users" | jq .

# 获取统计信息
echo "6. 获取统计信息测试"
curl -s "$BASE_URL/api/users/stats" | jq .

# 删除用户
echo "7. 删除用户测试"
curl -s -X DELETE "$BASE_URL/api/users/$USER_ID"
echo "用户已删除"

echo "API 功能测试完成!"

7.2 压力测试

#!/bin/bash
# load-test.sh

echo "=== Spring Native 压力测试 ==="

# 使用 Apache Bench 进行压力测试
echo "开始压力测试(1000 请求,并发 10)..."
ab -n 1000 -c 10 http://localhost:8080/health

echo "开始 API 压力测试(500 请求,并发 5)..."
ab -n 500 -c 5 -H "Content-Type: application/json" \
    -p user-data.json http://localhost:8080/api/users

8. 核心要点

8.1 架构设计

  1. 分层架构:采用经典的 MVC 分层架构,便于维护和扩展
  2. 依赖注入:充分利用 Spring 的 IoC 容器管理组件依赖
  3. 配置管理:使用 @ConfigurationProperties 实现类型安全的配置
  4. 异常处理:统一的异常处理机制,提供友好的错误响应

8.2 最佳实践

  1. 原生提示:使用 @NativeHint 注解提供编译时提示
  2. 资源管理:合理配置静态资源和反射配置
  3. 性能优化:避免使用动态特性,优先使用编译时确定的代码
  4. 测试覆盖:确保核心功能有完整的测试覆盖

8.3 开发注意事项

  1. 反射限制:避免使用运行时反射,使用编译时代码生成
  2. 动态代理:谨慎使用动态代理,优先使用接口代理
  3. 类路径扫描:避免运行时类路径扫描,使用显式配置
  4. 序列化:确保序列化类在编译时可见

9. 下一步学习

  1. 原生镜像构建:学习 GraalVM 原生镜像构建过程和优化技巧
  2. 配置优化:深入了解原生镜像配置文件的编写和调优
  3. 性能调优:掌握原生镜像的性能分析和优化方法
  4. 部署实践:学习原生镜像在容器化环境中的部署策略

通过本章的学习,你已经掌握了 Spring Native 基础应用的开发方法。接下来我们将学习如何构建和优化原生镜像。