Hibernate 数据库服务关闭时允许EntityManagerFactory注入为null

Hibernate 数据库服务关闭时允许EntityManagerFactory注入为null,hibernate,jpa,dependency-injection,jersey,jax-rs,Hibernate,Jpa,Dependency Injection,Jersey,Jax Rs,我有一个Jersey web服务,它使用Hibernate进行一些持久化。我使用hk2提供程序逻辑实现了EntityManagerFactory的创建/处理。我发现了堆栈溢出,这极大地帮助保持了较低的DB连接数。我不想强迫用户使用DB,所以我希望代码能够优雅地处理这种情况。然而,除了不得不注释我的@Inject注释外,我似乎无法理解它。有人知道如何使用自定义@Inject并将其编码为允许为null吗 当Persistence.create失败时,我试图在DBManager中捕获该异常,并在我的W

我有一个Jersey web服务,它使用Hibernate进行一些持久化。我使用hk2提供程序逻辑实现了EntityManagerFactory的创建/处理。我发现了堆栈溢出,这极大地帮助保持了较低的DB连接数。我不想强迫用户使用DB,所以我希望代码能够优雅地处理这种情况。然而,除了不得不注释我的@Inject注释外,我似乎无法理解它。有人知道如何使用自定义@Inject并将其编码为允许为null吗

当Persistence.create失败时,我试图在DBManager中捕获该异常,并在我的WebServiceClass中检查null。但是它在@Inject行崩溃,并且没有捕获异常。我查看了findOrCreate null异常,发现有一个名为SupportsAllCreation()的方法,但没有找到如何使用它的示例

这就是我的代码的样子:

使用HK2的可注入DB提供程序:

public class DbManager 
        implements Factory<EntityManagerFactory>
{
   private static EntityManagerFactory factory = null;

   @Inject
   public DbManager()
   {
      try
      {
         factory = Persistence.createEntityManagerFactory("myapp");
      }
      catch ( Exception eee )
      {
         // just means DB is not connected which I want to allow
         System.out.println("No DB, that should be okay");
      }
   }

   @Override
   public EntityManagerFactory provide() {
      return factory;
   }

   @Override
   public void dispose(EntityManagerFactory emf) {
      if ( emf != null && emf.isOpen() )
      {
         emf.close();
      }
   }

   public EntityManagerFactory getEntityMgrFactory()
   {
      return factory;
   }
}
然后是这样使用的:

@Singleton
@Path("myservice")
public class WebServiceClass
{

   // NOTE: Right now I have to comment this to run without a DB
   @Inject
   private EntityManagerFactory entityManagerFactory = null;
   ...
// factory wrapper
public class EMFHolder {
   private EntityManagerFactory emf;
   public EMFHolder(EntityManagerFactory emf) { this.emf = emf;}
   public EntityManagerFactory getEmf() { return this.emf; 
}

// provider
public class DbManager implements Factory<EntityManagerFactory> {
 // ... 
   @Override
   public EMFHolder provide() {
      return new EMFHolder(factory);
   }
 // ...
}

// using factory if not null
public class WebServiceClass
{
   @Inject
   private EMFHolder emfHolder;

   public void doComethingWithEMF() {
     if (emfHolder.getEmf() != null) {
        // do something with the factory...
     }
   }
}
我得到的例外是

java.lang.IllegalStateException: Context 
 org.jvnet.hk2.internal.SingletonContext@6cae5847 findOrCreate returned a null for 
descriptor SystemDescriptor(
    implementation=com.db.DbManager
    contracts={javax.persistence.EntityManagerFactory}
    scope=javax.inject.Singleton
    qualifiers={}
    descriptorType=PROVIDE_METHOD
    descriptorVisibility=NORMAL
    metadata=
    rank=0
    loader=org.glassfish.hk2.utilities.binding.AbstractBinder$2@7050f2b1
    proxiable=null
    proxyForSameScope=null
    analysisName=null
    id=145
    locatorId=0
    identityHashCode=863132354
    reified=true)
    at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2075)
...
你可以看一看


使用该模式,如果不存在数据库,您可以在配置中注册
工厂的
空对象
实现
,而不是
DbManager

,您需要的是EMF依赖项的动态注入。通常,所有注入都是静态的,这意味着在创建依赖于注入的对象时,所有依赖项都是关联的

使用任何依赖项注入机制(不仅仅是HK2)的一个简单解决方案是创建一个包装器对象,该对象将保存对真实依赖项的引用,如果依赖项不可用,则为null。通过将EntityManagerFactory包装成一个或零个元素的集合,也可以实现同样的效果。它可能是这样的:

@Singleton
@Path("myservice")
public class WebServiceClass
{

   // NOTE: Right now I have to comment this to run without a DB
   @Inject
   private EntityManagerFactory entityManagerFactory = null;
   ...
// factory wrapper
public class EMFHolder {
   private EntityManagerFactory emf;
   public EMFHolder(EntityManagerFactory emf) { this.emf = emf;}
   public EntityManagerFactory getEmf() { return this.emf; 
}

// provider
public class DbManager implements Factory<EntityManagerFactory> {
 // ... 
   @Override
   public EMFHolder provide() {
      return new EMFHolder(factory);
   }
 // ...
}

// using factory if not null
public class WebServiceClass
{
   @Inject
   private EMFHolder emfHolder;

   public void doComethingWithEMF() {
     if (emfHolder.getEmf() != null) {
        // do something with the factory...
     }
   }
}
//工厂包装器
公共类EMFHolder{
私人实体管理工厂emf;
公共EMFHolder(EntityManagerFactory emf){this.emf=emf;}
public EntityManagerFactory getEmf(){返回this.emf;
}
//提供者
公共类DbManager实现工厂{
// ... 
@凌驾
公共EMFHolder提供(){
退回新的EMFHolder(工厂);
}
// ...
}
//如果不为空,则使用工厂
公共类WebServiceClass
{
@注入
私人电话机;
public void doComethingWithEMF(){
if(emfHolder.getEmf()!=null){
//对工厂做点什么。。。
}
}
}

也看看HK2,但我认为它不允许您从
provide
方法返回空值。

因此,以您的示例为例,您是说如果EMF创建失败,您仍然希望它正常工作,这意味着注入将为空?这有什么好处?我理解正确吗uess问题是,如果没有db,用户将如何与服务交互?对端点的调用将返回什么?是的,我希望它在EMF创建失败时正常工作。对端点的调用将向用户返回一些数据,这些数据可能会保留,也可能不会保留,这取决于db是否已安装并正在运行。我可以使用更多详细信息。我创建NullableDbMgr时出错,但提供()方法应该为EntityManagerFactory返回null,对吗?如果是,它会导致相同的问题。你是说我应该提供一些不同的东西吗?如果是,这不会破坏提供程序的有效性吗?是的,你还应该创建
EntityManagerFactory的
null对象
实现,以便在没有这应该警告你,如果<代码> EntIdMaulePrimeStudio<代码>不是我自己的接口,为什么我直接在我的消费类?AppAt中使用它,为了解决你的情况,你也可以考虑使用内存数据库。空对象的想法是,你不会从No.>提供“< /Cord>”方法返回null,但是你将创建你自己的IMP。
EntityManagerFactory
接口的实现,带有空方法(例如,可能引发运行时异常)。在客户端代码中,您将尝试检查是否接收到此类空对象。如果是,则表示没有与数据库的连接。否则,您将像往常一样使用注入的EMF对象。