我试图弄清楚如何处理CDI。我正在开发一个用户可以连接到多个数据库的应用程序。应用程序询问他们想要连接到哪个,他们还可以断开连接并连接到不同的数据库。这是一个使用Seam for CDI和Hibernate for JPA的Java SE应用程序。我想弄清楚的是如何利用CDI连接@PersistenceContext,但也使其动态化,以便可以访问不同的数据库。我不确定我会用CDI做的模式或技术。思考?
答案 0 :(得分:2)
所以我想我通过javax.enterprise.inject.Instance
想出了我想做的事情。首先定义一个简单的bean:
@Alternative
public class Foo {
private int value;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
它定义为@Alternative
,因此CDI不会在此与生产者方法之间混淆(如下所示)。一个更好的解决方案是定义Foo
作为接口,然后FooImpl
将使用@Typed
进行注释,因此CDI认为它只是FooImpl
bean类型。无论如何,接下来是生产者类。
@ApplicationScoped
public class FooProducer {
private int value;
public FooProducer() {
value = -1;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Produces
public Foo getFoo() {
Foo p = new Foo();
p.setValue(getValue());
return p;
}
}
getFoo()
方法生成具有不同值的新Foo
对象。可以通过setValue(int)
方法更改该值。接下来,我使用javax.enterprise.inject.Instance
来注入Foo
。
@Inject
Instance<Foo> fooInstance;
@Inject
FooProducer fooProducer;
....
fooProducer.setValue(10);
Foo foo = fooInstance.get();
System.out.printf("foo = %s, %d\n", foo.getValue());
fooProducer.setValue(10000);
foo = fooInstance.get();
System.out.printf("foo = %s, %d\n", foo.getValue());
这里我使用注入的fooProducer.setValue()
方法来更改生成器生成Foo
的方式。当fooInstance.get()
被调用时,第一次Foo
将包含值10,第二次将值为10000。
鉴于这个简单的例子,很容易应用于在运行时将EntityManager
实例提供给不同的数据库。 1}}产生EntityManager
而不是太多的代码还有一些。
答案 1 :(得分:0)
PersistenceContext由EJB容器处理。由于您不在EJB容器中,请忘记持久化上下文并考虑使用CDI生成器。
@ApplicationScoped
public class EntityManagerFactoryProvider {
private EntityManagerFactory emf;
public void voidApplicationEMF() {
//load the EMF here based on dynamic properties
this.emf = Persistence.createEntityManagerFactpry(Map of loaded properties);
}
@Produces
public EntityManager em() {
return emf.createEntityManager();
}
}
然后在你的代码中的某个地方
@SessionScoped
public class MyEntityController {
@Inject
private EntityManager emf;
}
处理交易等仍有问题。
在JSE环境中,您必须显式启动并提交/回滚事务。 由于您使用的是CDI,因此可以根据需要使用拦截器来启动/检查事务状态和回滚/提交。
@Interceptor
public class MyInterceptor {
@Inject
private EntityManager em;
@AroundInvoke
public Object intercept(InvocationContext ic) {
try {
//initiate transaction
em.getTransaction().start ....
return ic.proceed();
}catch(Exception ex) { //rollback if necessary }
finally {//commit transaction if necessary }
}
}