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

时间:2015-09-30 05:50:44

标签: hibernate jpa dependency-injection jersey jax-rs

我有一个使用Hibernate做一些持久性的Jersey Web服务。我已经使用hk2提供程序逻辑实现了EntityManagerFactory的创建/处理我发现了堆栈溢出,这极大地帮助保持了较低的DB连接数。我不想强迫用户拥有数据库,所以我希望代码能够优雅地处理这种情况。但是,除了必须注释掉我的@Inject注释之外,我似乎无法弄明白。任何人都知道如何使用自定义@Inject并对其进行编码以允许它为空?

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

这就是我的代码:

使用HK2的可注入数据库提供程序:

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;
   }
}

然后,这里是如何在Jersey应用程序中创建提供程序:

@ApplicationPath("rest")
public class MyApplication extends ResourceConfig 
{
    public MyApplication()
    {

        ....

    // Provider of DB
    this.register( new AbstractBinder()
    {
       @Override
       public void configure()
       {
 bindFactory(DbManager.class).to(EntityManagerFactory.class).in(Singleton.class);
       }
    });
}

然后就像这样使用:

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

   // NOTE: Right now I have to comment this to run without a DB
   @Inject
   private EntityManagerFactory entityManagerFactory = null;
   ...

我得到的例外是......

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)
...

2 个答案:

答案 0 :(得分:2)

您想要的是动态注入EMF依赖项。通常,所有注入都是静态的,这意味着当创建依赖于它们的对象时,所有依赖关系都会被连接。

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

// 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...
     }
   }
}

另请查看HK2 Iterable Provider,但我认为它不允许您从provide方法返回空值。

答案 1 :(得分:0)

您可以查看Null Object pattern

使用该模式,如果不存在数据库,您可以在配置中注册Null Object Factory<EntityManagerFactory>实施而不是DbManager