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

Tomcat启动SpringMVC项目时JPA EntityManagerFactory配置报NPE错误

问题描述

启动Tomcat时抛出以下异常:

java.lang.NullPointerException: Cannot invoke "org.hibernate.boot.spi.MetadataImplementor.getEntityBindings()" because "this.metadata" is null

异常发生在Spring MVC项目中通过编程式配置Spring JPA的EntityManagerFactory阶段。相关配置代码如下:

@Configuration
public class JpaConfig {

    private static final Logger logger = LoggerFactory.getLogger(JpaConfig.class);

    @Bean
    public DataSource dataSource() {
        try {
             SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
             Class<? extends Driver> driver = (Class<? extends Driver>) Class.forName("org.h2.Driver");
             dataSource.setDriverClass(driver);
             dataSource.setUrl("jdbc:h2:mem:test");
             dataSource.setUsername("SA");
             dataSource.setPassword("");
             return dataSource;
        } catch (Exception e) {
            System.out.println( e );
            logger.error("Embedded DataSource bean cannot be created!", e);
            return null;
        }
    }

    @Bean
    public Properties hibernateProperties() {
        Properties hibernateProp = new Properties();
        hibernateProp.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        hibernateProp.put("hibernate.hbm2ddl.auto", "create-drop");
        hibernateProp.put("hibernate.show_sql", true);
        hibernateProp.put("hibernate.max_fetch_depth", 3);
        hibernateProp.put("hibernate.jdbc.batch_size", 10);
        hibernateProp.put("hibernate.jdbc.fetch_size", 50);
        return hibernateProp;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory());
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
        return vendorAdapter;
    }

    @Bean
    public EntityManagerFactory entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setPackagesToScan("com.apress.prospring5.ch16.entities");
        factoryBean.setDataSource(dataSource());
        factoryBean.setJpaProperties(hibernateProperties());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
        factoryBean.afterPropertiesSet();
        return factoryBean.getNativeEntityManagerFactory();
    }
}

已尝试多种DataSource配置方式,问题仍未解决。


问题原因与修复

核心原因

异常源于手动调用LocalContainerEntityManagerFactoryBean.afterPropertiesSet()并直接获取NativeEntityManagerFactory,绕过了Spring容器对FactoryBean的生命周期管理。LocalContainerEntityManagerFactoryBean是Spring提供的FactoryBean实现,负责完整的JPA初始化流程(包括Hibernate元数据构建),手动触发初始化无法覆盖所有Spring容器的回调逻辑,导致Hibernate内部Metadata实例未被正确初始化,最终抛出空指针。

修复方案

修改entityManagerFactory的Bean定义,直接返回LocalContainerEntityManagerFactoryBean实例,由Spring容器自动处理其生命周期:

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
    factoryBean.setPackagesToScan("com.apress.prospring5.ch16.entities");
    factoryBean.setDataSource(dataSource());
    factoryBean.setJpaProperties(hibernateProperties());
    factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
    // 移除手动调用的afterPropertiesSet(),交由Spring自动处理初始化
    return factoryBean;
}

同时修改事务管理器的Bean定义,通过Spring自动注入EntityManagerFactory(Spring会自动从FactoryBean中获取实际的EntityManagerFactory实例):

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    return new JpaTransactionManager(entityManagerFactory);
}

额外优化

  1. DataSource异常处理:当前dataSource()方法在异常时返回null,会导致后续依赖Bean初始化失败,建议直接抛出异常让Spring感知错误:
@Bean
public DataSource dataSource() throws ClassNotFoundException {
    SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
    Class<? extends Driver> driver = (Class<? extends Driver>) Class.forName("org.h2.Driver");
    dataSource.setDriverClass(driver);
    dataSource.setUrl("jdbc:h2:mem:test");
    dataSource.setUsername("SA");
    dataSource.setPassword("");
    return dataSource;
}
  1. Logger初始化:确保配置类中正确初始化Logger(如LoggerFactory.getLogger(JpaConfig.class))。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:26:03