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); }
额外优化
- 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; }
- Logger初始化:确保配置类中正确初始化Logger(如
LoggerFactory.getLogger(JpaConfig.class))。
内容的提问来源于stack exchange,提问作者Dinesh
相关产品推荐
相关产品推荐

