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

GraalVM编译Spring Boot应用启动报错:ConfigLog不是托管类型

GraalVM编译Spring Boot应用启动报错:ConfigLog不是托管类型

最近我在把基于Java 17、Spring Boot 3.4.1的项目迁移到GraalVM上,用OpenJDK 17.0.14运行时一切正常,用GraalVM也能顺利完成构建,但运行生成的可执行文件时直接报错了,提示ConfigLog不是托管类型。我用的GraalVM版本是GraalVM Liberica-NIK-23.0.7-1 (build 17.0.14+10-LTS)。

核心报错堆栈

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configLogRepository': Not a managed type: class com.project.demo.module.configLogs.domain.ConfigLog
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1808)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:289)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1573)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1519)
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveValue(AutowiredFieldValueResolver.java:186)
        ... 192 more
Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.project.demo.module.configLogs.domain.ConfigLog
        at org.hibernate.metamodel.model.domain.internal.JpaMetamodelImpl.managedType(JpaMetamodelImpl.java:223)
        at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.managedType(MappingMetamodelImpl.java:470)
        at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.managedType(MappingMetamodelImpl.java:100)
        at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:82)
        at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:69)
        at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:251)
        at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:215)
        at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:198)
        at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:1)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:386)
        at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$4(RepositoryFactoryBeanSupport.java:350)
        at org.springframework.data.util.Lazy.getNullable(Lazy.java:135)
        at org.springframework.data.util.Lazy.get(Lazy.java:113)
        at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:356)
        at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:132)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
        ... 201 more

我的相关配置与代码

数据库配置类(DatabaseConfiguration)

package com.project.demo.config;

import com.zaxxer.hikari.HikariDataSource;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;

import lombok.AllArgsConstructor;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.context.EnvironmentAware;
import jakarta.persistence.EntityManagerFactory;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "postgresEntityManagerFactory",
        transactionManagerRef = "postgresTransactionManager",
        basePackages = "com.project.demo")
@AllArgsConstructor
public class DatabaseConfiguration implements EnvironmentAware {

    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Primary
    @Bean(name = "postgresDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public HikariDataSource dataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class)
                .driverClassName("org.postgresql.Driver")
                .url("jdbc:postgresql://localhost:5432/demo")
                .username(environment.getProperty("spring.datasource.username"))
                .password(environment.getProperty("spring.datasource.password")).build();
    }

    public Map<String, String> hikariConfig() {
        Map<String, String> properties = new HashMap<>();
        properties.put("driverClassName", "org.postgresql.Driver");
        properties.put("url", "jdbc:postgresql://localhost:5432/demo");
        properties.put("username", environment.getProperty("spring.datasource.username"));
        properties.put("password", environment.getProperty("spring.datasource.password"));
        properties.put("minimumIdle", "5"); properties.put("maximumPoolSize", "8");
        properties.put("idleTimeout", "30000");
        properties.put("poolName", "SpringBootJPAHikariCP");
        properties.put("maxLifetime", "600000"); properties.put("keepaliveTime", "60000");
        properties.put("connectionTimeout", "30000");
        properties.put("initializationFailTimeout", "10000");
        properties.put("minimumIdle", "10000");
        return properties;
    }

    @Bean(name = "postgresTransactionManager")
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }

    @Bean(name = "postgresEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder entityManagerFactoryBuilder, @Qualifier("postgresDataSource") DataSource dataSource) {
        return entityManagerFactoryBuilder.dataSource(dataSource).packages("com.project.demo").properties(hikariConfig()).build();
    }
}

ConfigLog实体类

package com.project.demo.module.configLogs.domain;

import com.project.demo.module.masters.constants.OperationType;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;

@Entity
@Table(name = "config_log")
@Getter
@Setter
public class ConfigLog {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "user_id")
    private Long userId;

    @Column(name = "company_id")
    private Long companyId;

    @Column(name = "operation_type")
    @Enumerated(value = EnumType.STRING)
    private OperationType operationType;

    @Column(name = "log_time")
    private LocalDateTime logTime = LocalDateTime.now();

    @Column(name = "json")
    private String json;

    @Override
    public String toString() {
        return "ConfigLog{" +
                "id=" + id +
                ", userId=" + userId +
                ", companyId=" + companyId +
                ", operationType=" + operationType +
                ", logTime=" + logTime +
                ", json='" + json + '\'' +
                '}';
    }
}

ConfigLogRepository类

package com.project.demo.module.configLogs.repository;

import com.project.demo.module.configLogs.domain.ConfigLog;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ConfigLogRepository extends JpaRepository<ConfigLog, Long> {
}

问题分析与解决方案

这个问题本质是GraalVM在编译原生镜像时,没有正确识别到JPA实体类的反射信息,导致Hibernate无法将其标记为托管类型。下面是几个可行的解决方案:

1. 显式在EntityManagerFactory中指定实体类

修改数据库配置类中的entityManagerFactory方法,在构建时显式添加实体类,让GraalVM编译时能明确扫描到:

@Bean(name = "postgresEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder entityManagerFactoryBuilder, @Qualifier("postgresDataSource") DataSource dataSource) {
    return entityManagerFactoryBuilder
            .dataSource(dataSource)
            .packages("com.project.demo")
            .properties(hikariConfig())
            // 显式添加实体类,多个的话可以用逗号分隔
            .classes(ConfigLog.class)
            .build();
}

2. 添加@RegisterReflectionForBinding注解

在Spring Boot主应用类上添加该注解,强制GraalVM保留实体类的反射元数据:

@SpringBootApplication
@RegisterReflectionForBinding(ConfigLog.class)
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

如果有多个实体类,可以用数组形式:@RegisterReflectionForBinding({ConfigLog.class, YourOtherEntity.class})

3. 优化Spring Boot原生镜像插件配置

如果你用的是Spring Boot的原生镜像插件,确保插件配置中包含必要的参数,帮助GraalVM识别实体类。比如Maven插件可以这样配置:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <nativeImage>
            <buildArgs>
                <!-- 指定实体类所在的包,确保扫描到 -->
                -H:IncludeResources=application.properties
                -H:Package=com.project.demo.module.configLogs.domain
            </buildArgs>
        </nativeImage>
    </configuration>
</plugin>

4. 确认注解正确性

虽然你的代码里已经用了Jakarta Persistence的注解(jakarta.persistence.*),但还是要确认没有混用旧的Javax注解,Spring Boot 3.x完全基于Jakarta EE,混用会导致识别问题。

备注:内容来源于stack exchange,提问作者Vibhor Verma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 17:58:04