IllegalArgumentException:不是托管类型:Spring GraalVM 原生编译中的实体

问题描述 投票:0回答:2

问题

我正在尝试使用 Spring Boot 3 和 GraalVM(sdkjava 22.3.2.r17-grl)本机编译来创建应用程序的本机可执行文件。

应用程序使用标准 SDK 正常运行,但是当我运行生成的可执行文件(

$ ./gradlew nativeCompile
的结果)时,我收到以下错误:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'carController': Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'carRepository': Not a managed type: class com.example.demo.domain.CarEntity
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:315) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:258) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:198) ~[na:na]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:947) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1214) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1158) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[demo:6.0.9]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) ~[demo:6.0.9]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:941) ~[demo:6.0.9]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608) ~[demo:6.0.9]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[demo:3.0.7]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) ~[demo:3.0.7]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[demo:3.0.7]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[demo:3.0.7]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1304) ~[demo:3.0.7]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1293) ~[demo:3.0.7]
        at com.example.demo.DemoApplication.main(DemoApplication.java:12) ~[demo:na]

关于申请

存储库https://github.com/BernardMenezes/spring-graalvm-demo

该应用程序有两个 JPA EntityManager,每个都在自己的配置类中配置:

N1数据源配置

package com.example.demo.config;

import com.example.demo.domain.CarEntity;
import com.example.demo.repo.CarRepository;
import com.zaxxer.hikari.HikariDataSource;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
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.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 javax.sql.DataSource;
import java.util.HashMap;
import java.util.Objects;

@Configuration
@EnableJpaRepositories(
        basePackageClasses = {CarRepository.class},
        entityManagerFactoryRef = "n1EntityManagerFactory",
        transactionManagerRef = "n1TransactionManager"
)
@RequiredArgsConstructor
@EnableTransactionManagement
public class N1DataSourceConfig {

    @Primary
    @Bean
    public DataSource n1DataSource() {

        HikariDataSource hikariDataSource = new HikariDataSource();
        hikariDataSource.setUsername("postgres");
        hikariDataSource.setPassword("postgres");
        hikariDataSource.setJdbcUrl("jdbc:postgresql://localhost:5432/n1");
        hikariDataSource.setMaximumPoolSize(10);
        return hikariDataSource;
    }

    @Primary
    @Bean
    public LocalContainerEntityManagerFactoryBean n1EntityManagerFactory(EntityManagerFactoryBuilder builder) {

        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("hibernate.physical_naming_strategy", "org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy");
        properties.put("hibernate.globally_quoted_identifiers", true);

        return builder
                .dataSource(n1DataSource())
                .persistenceUnit("n1")
                .packages(
                        CarEntity.class.getPackage().getName()
                )
                .properties(properties)
                .build();
    }

    @Primary
    @Bean
    public PlatformTransactionManager n1TransactionManager(
            final @Qualifier("n1EntityManagerFactory") LocalContainerEntityManagerFactoryBean n1EntityManagerFactory) {
        return new JpaTransactionManager(Objects.requireNonNull(n1EntityManagerFactory.getObject()));
    }
}

N2数据源配置

package com.example.demo.config;

@Configuration
@EnableJpaRepositories(
        basePackageClasses = {},
        entityManagerFactoryRef = "n2EntityManagerFactory",
        transactionManagerRef = "n2TransactionManager"
)
@RequiredArgsConstructor
@EnableTransactionManagement
public class N2DataSourceConfig {

    @Bean
    public DataSource n2DataSource() {

        HikariDataSource hikariDataSource = new HikariDataSource();
        hikariDataSource.setUsername("postgres");
        hikariDataSource.setPassword("postgres");
        hikariDataSource.setJdbcUrl("jdbc:postgresql://localhost:5432/n2");
        hikariDataSource.setMaximumPoolSize(10);
        return hikariDataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean n2EntityManagerFactory(EntityManagerFactoryBuilder builder) {

        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("hibernate.physical_naming_strategy", "org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy");
        properties.put("hibernate.globally_quoted_identifiers", true);

        return builder
                .dataSource(n2DataSource())
                .persistenceUnit("n2")
                .packages(
                        RevisionEntity.class.getPackage().getName()
                )
                .properties(properties)
                .build();
    }

    @Bean
    public PlatformTransactionManager n2TransactionManager(
            final @Qualifier("n1EntityManagerFactory") LocalContainerEntityManagerFactoryBean n1EntityManagerFactory) {
        return new JpaTransactionManager(Objects.requireNonNull(n1EntityManagerFactory.getObject()));
    }
}

汽车实体

package com.example.demo.domain;

import jakarta.persistence.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;

import java.time.ZonedDateTime;
import java.util.UUID;

@Entity
@Table(name = "car")
public class CarEntity {

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

    @CreatedDate
    @Column(columnDefinition = "timestamp")
    private ZonedDateTime createdAt;

    @LastModifiedDate
    @Column(columnDefinition = "timestamp")
    private ZonedDateTime lastModified;

    @Column(unique = true)
    private String name;

    @Version
    private Integer version;

}

汽车存储库

package com.example.demo.repo;

import com.example.demo.domain.CarEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repository
public interface CarRepository extends JpaRepository<CarEntity, UUID> {
}

汽车控制器

package com.example.demo.api;

import com.example.demo.domain.CarEntity;
import com.example.demo.repo.CarRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class CarController {

    private final CarRepository carRepository;

    @GetMapping("/car")
    public List<CarEntity> getCar() {
        return carRepository.findAll();
    }

}

修订实体

package com.example.demo.domain;

import jakarta.persistence.*;
import lombok.Setter;

import java.util.Date;

@Entity
@Table(name = "revision")
public class RevisionEntity {

    @Id
    @GeneratedValue
    private long id;

    @Temporal(TemporalType.TIMESTAMP)
    private Date timestamp;

    @Setter
    private String context;

}

演示应用程序

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

构建.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.0.7'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'org.graalvm.buildtools.native' version '0.9.20'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    implementation 'org.springframework.boot:spring-boot-starter-web'

    runtimeOnly 'org.postgresql:postgresql'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}


我希望能够使用本机可执行文件运行应用程序,就像使用标准 JDK 运行一样。

spring-boot spring-data-jpa graalvm graalvm-native-image
2个回答
1
投票

您的 LocalContainerEntityManagerFactoryBean 缺少 PersistenceManagedTypes 参数。我创建了一个示例应用程序,如何通过 Spring Boot 和本机映像使用多个数据库here,它还展示了如何设置自定义数据源。 PersistenceManagedTypes 的用法也记录在 spring-docs 中。我也花了一段时间才弄清楚这一点。


0
投票

我遵循了大部分答案,但没有解决我的问题。

就我而言,答案很简单:

Project details:
Spring Boot, Maven, Java 17, Multi-Module

我必须改变

形式:

import javax.persistence.*;

至:

 import jakarta.persistence.*;
© www.soinside.com 2019 - 2024. All rights reserved.