CDI根据用户输入注入@PersistenceContext

时间:2014-09-30 02:45:33

标签: jpa cdi inject

我试图弄清楚如何处理CDI。我正在开发一个用户可以连接到多个数据库的应用程序。应用程序询问他们想要连接到哪个,他们还可以断开连接并连接到不同的数据库。这是一个使用Seam for CDI和Hibernate for JPA的Java SE应用程序。我想弄清楚的是如何利用CDI连接@PersistenceContext,但也使其动态化,以便可以访问不同的数据库。我不确定我会用CDI做的模式或技术。思考?

2 个答案:

答案 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实例提供给不同的数据库。 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 }
  }
}