当数据库服务关闭时允许 EntityManagerFactory 注入为 null
Allow EntityManagerFactory injection to be null when database service is off
我有一个 Jersey Web 服务,它使用 Hibernate 来做一些持久性。我已经使用 hk2 提供程序逻辑实现了 EntityManagerFactory 的 creation/disposal 我发现了堆栈溢出,这极大地帮助保持了较低的数据库连接数。我不想强迫用户拥有数据库,所以我希望代码能够优雅地处理这种情况。但是,除了必须注释掉我的 @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@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)
...
你可以看看Null Object pattern。
使用该模式,如果不存在数据库,您可以在配置中注册 Factory<EntityManagerFactory>
的 Null Object
实现,而不是 DbManager
。
你想要的是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
方法中 return 空值。
我有一个 Jersey Web 服务,它使用 Hibernate 来做一些持久性。我已经使用 hk2 提供程序逻辑实现了 EntityManagerFactory 的 creation/disposal 我发现了堆栈溢出,这极大地帮助保持了较低的数据库连接数。我不想强迫用户拥有数据库,所以我希望代码能够优雅地处理这种情况。但是,除了必须注释掉我的 @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@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)
...
你可以看看Null Object pattern。
使用该模式,如果不存在数据库,您可以在配置中注册 Factory<EntityManagerFactory>
的 Null Object
实现,而不是 DbManager
。
你想要的是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
方法中 return 空值。