Quarkus中Persistence.createEntityManagerFactory调用触发NPE问题
问题答案
你的推测完全属实:Quarkus 框架下的 quarkus-hibernate-orm 模块不支持手动调用 Persistence.createEntityManagerFactory() 方法动态初始化 EntityManagerFactory。
报错原因
从异常栈可以看到,调用链最终走到了 Quarkus 自定义的 FastBootHibernatePersistenceProvider 实现类,这个类是 Quarkus 替换原生 Hibernate 持久化提供者的定制实现:
- Quarkus 为了实现极速启动、原生镜像编译支持,会在项目构建阶段就完成所有持久化单元的配置解析、实体扫描、字节码增强工作,所有 EntityManagerFactory 实例都在应用启动阶段由 ARC 容器统一初始化托管。
- 这个定制的持久化提供者根本没有实现运行时动态创建持久化单元的逻辑,手动调用创建方法时,它拿不到构建阶段预先生成的持久化单元配置元数据,直接触发空指针异常。
你示例代码中通过 @Inject 注入 EntityManagerFactory 的接口能正常运行,就是 Quarkus 官方支持的唯一标准使用方式。
第三方库适配方案
不是所有调用了 Persistence.createEntityManagerFactory() 的第三方库都必须改造源码,分两种场景处理:
- 如果第三方库调用该方法的目的只是获取一个已存在的指定名称持久化单元的 EntityManagerFactory 实例,而非自己从头初始化一套独立的持久化单元,不需要修改库源码:你可以通过自定义 JPA
PersistenceProviderResolver适配层,在第三方库调用该方法时,直接返回 Quarkus 容器中已经初始化好的对应 EntityManagerFactory 实例即可。大部分传统Java库写死调用该方法只是为了拿实例,不是要动态新建持久化单元,这种适配方式成本极低。 - 如果第三方库调用该方法的目的是动态创建独立的、和应用托管配置隔离的 EntityManagerFactory(比如运行时动态添加数据源、动态生成实体映射的特殊场景),Quarkus 原生的 Hibernate ORM 托管模式无法支持这种需求:要么修改第三方库,让它支持接收外部注入的 EntityManagerFactory 实例;要么放弃 Quarkus 对 Hibernate 的托管能力,把 Hibernate 作为普通第三方依赖引入自行管理生命周期,但这种方式会丢失 Quarkus 提供的所有 Hibernate 相关优化(启动加速、原生编译支持、自动事务集成等),不推荐使用。
问题复现代码参考
package com.example; import javax.inject.Inject; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("/hello") public class ExampleResource { @Inject EntityManagerFactory emf; @GET @Produces(MediaType.TEXT_PLAIN) public String working() { EntityManager manager = emf.createEntityManager(); return manager.createNativeQuery("SELECT * from example").getResultList().toString(); } @GET @Path("/test") @Produces(MediaType.TEXT_PLAIN) public String notWorking() { EntityManagerFactory emflocal = Persistence.createEntityManagerFactory("ExampleDatasource"); EntityManager manager = emflocal.createEntityManager(); return manager.createNativeQuery("SELECT * from example").getResultList().toString(); } }
核心报错栈
Caused by: java.lang.NullPointerException at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(FastBootHibernatePersistenceProvider.java:169) at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.createEntityManagerFactory(FastBootHibernatePersistenceProvider.java:65) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:80) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
内容的提问来源于stack exchange,提问作者marandi
相关产品推荐
相关产品推荐

