You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GraalVM原生镜像运行Java17-SpringBoot3-Ehcache项目报错

Ehcache + GraalVM原生镜像启动失败:序列化器构造器异常

环境与配置

  • JDK版本:Java 17
  • Spring Boot版本:3.x
  • 缓存方案:Spring Boot Cache + Ehcache 3.10.8
  • 构建方式:GraalVM原生镜像,通过Docker Compose构建运行

Maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.10.8</version>
</dependency>

Ehcache配置类

import java.time.Duration;
import javax.cache.CacheManager;
import javax.cache.Caching;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.jsr107.Eh107Configuration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@EnableCaching
@Configuration
public class EhcacheConfiguration {

  @Bean
  public CacheManager EhcacheManager() {
    var cachingProvider = Caching.getCachingProvider();
    var cacheManager = cachingProvider.getCacheManager();

    cacheManager.createCache("myTestOne",
        Eh107Configuration.fromEhcacheCacheConfiguration(
            CacheConfigurationBuilder
                .newCacheConfigurationBuilder(Integer.class,
                    MyObject.class,
                    ResourcePoolsBuilder.newResourcePoolsBuilder()
                        .offheap(100, MemoryUnit.MB)
                        .build())
                .withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(23)))
                .build()
        )
    );

    return cacheManager;
  }

}

Spring Native插件配置

<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>build-native</id>
            <goals>
                <goal>compile-no-fork</goal>
            </goals>
            <phase>package</phase>
        </execution>
    </executions>
</plugin>

Docker相关配置

Dockerfile

FROM ghcr.io/graalvm/graalvm-ce:ol7-java17-22.3.0 as build

RUN gu install native-image

RUN yum install -y zip unzip libstdc++-static freetype-devel

WORKDIR /app

COPY mvnw .
COPY .mvn .mvn

COPY pom.xml .

RUN chmod +x ./mvnw

COPY src src

RUN ./mvnw clean package -DskipTests -Pnative

ENTRYPOINT ["sh", "-c" ,"./target/test-app-one"]

docker-compose.yml

services:
  app-server:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    restart: always

问题现象

执行docker-compose up --build后,镜像构建成功,但应用启动失败,核心报错:

Caused by: java.lang.IllegalArgumentException: The serializer: org.ehcache.impl.serialization.PlainJavaSerializer does not have a constructor that takes in a ClassLoader.

非原生镜像运行正常,移除缓存依赖后原生镜像也能正常启动。


解决方案

原因分析

GraalVM原生镜像环境下,Ehcache默认使用的PlainJavaSerializer不满足序列化器的构造器要求——需要提供一个接收ClassLoader的构造方法,而原生镜像的类加载机制与标准JVM不同,导致该序列化器无法正常初始化。

修复步骤

  1. 显式指定兼容原生镜像的序列化器
    为缓存配置添加自定义序列化器,使用Ehcache的DefaultSerializer(也可自行实现序列化器,确保包含ClassLoader参数的构造方法)。修改Ehcache配置类:
import org.ehcache.impl.serialization.DefaultSerializer;
// ... 其他导入

@Bean
public CacheManager EhcacheManager() {
    var cachingProvider = Caching.getCachingProvider();
    var cacheManager = cachingProvider.getCacheManager();

    // 配置键和值的序列化器
    var cacheConfig = CacheConfigurationBuilder
        .newCacheConfigurationBuilder(Integer.class, MyObject.class,
            ResourcePoolsBuilder.newResourcePoolsBuilder().offheap(100, MemoryUnit.MB))
        .withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(23)))
        // 显式指定序列化器
        .withKeySerializer(new DefaultSerializer<>(Integer.class))
        .withValueSerializer(new DefaultSerializer<>(MyObject.class))
        .build();

    cacheManager.createCache("myTestOne", Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfig));

    return cacheManager;
}
  1. 添加GraalVM原生镜像元数据支持
    Spring Boot 3.x结合GraalVM时,需确保Ehcache相关类被正确处理:

    • 添加spring-boot-starter-aot依赖,自动生成原生镜像所需配置:
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aot</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    • 若自动生成不充分,手动创建resources/META-INF/native-image/reflect-config.json,补充反射规则:
    [
        {
            "name": "org.ehcache.impl.serialization.DefaultSerializer",
            "constructors": [
                {
                    "parameters": ["java.lang.Class", "java.lang.ClassLoader"]
                }
            ]
        },
        {
            "name": "com.test.testappone.MyObject",
            "allDeclaredConstructors": true,
            "allDeclaredFields": true,
            "allDeclaredMethods": true
        }
    ]
    
  2. 升级Ehcache版本(可选)
    升级Ehcache到3.12+等最新稳定版,新版本对GraalVM原生镜像兼容性更好,可减少手动配置需求。

  3. 验证构建与启动
    重新执行docker-compose up --build,确认应用正常启动且缓存功能可用。


内容的提问来源于stack exchange,提问作者John Dillard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:25:28