Jpa CDI根据用户输入注入@PersistenceContext

Jpa CDI根据用户输入注入@PersistenceContext,jpa,cdi,inject,Jpa,Cdi,Inject,我想知道如何使用CDI。我正在开发一个应用程序,用户可以连接到多个数据库。应用程序询问他们想要连接到哪个数据库,他们也可以断开连接并连接到另一个数据库。这是一个JavaSE应用程序,使用Seam进行CDI,使用Hibernate进行JPA。我想弄明白的是如何利用CDI连接@PersistenceContext,同时使其动态化,以便可以访问不同的数据库。我只是不确定我会用什么样的模式或技术来处理CDI。想法 PersistenceContext由EJB容器处理。由于您不在EJB容器中,请忽略持久性

我想知道如何使用CDI。我正在开发一个应用程序,用户可以连接到多个数据库。应用程序询问他们想要连接到哪个数据库,他们也可以断开连接并连接到另一个数据库。这是一个JavaSE应用程序,使用Seam进行CDI,使用Hibernate进行JPA。我想弄明白的是如何利用CDI连接@PersistenceContext,同时使其动态化,以便可以访问不同的数据库。我只是不确定我会用什么样的模式或技术来处理CDI。想法

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

所以我想我通过使用
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;
    }
}
它被定义为一个
@替代方法
,因此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());
@Inject
实例-实例;
@注入
食品生产者;
....
食品生产者设定值(10);
Foo-Foo=fooInstance.get();
System.out.printf(“foo=%s,%d\n”,foo.getValue());
食品生产者设定值(10000);
foo=fooInstance.get();
System.out.printf(“foo=%s,%d\n”,foo.getValue());
这里我使用注入的
fooProducer.setValue()
方法来更改生产者将如何生成
Foo
。当第一次调用
fooInstance.get()
时,
Foo
将包含值10,第二次将包含值10000


给出这个简单的示例,在运行时很容易将
EntityManager
实例应用到不同的数据库。生成
EntityManager
的代码还有一点,但不是太多。

持久化上下文由EJB容器处理
-这是不正确的。JPA是一个独立于EJB的规范,持久性上下文通常由JPA实现中特定于Java EE容器的部分设置。@ArjanTijms实际上JPA规范是EJB规范的一部分,只有规范文档是独立的。我不清楚如何实现您注释为“//基于动态属性在此处加载EMF”的部分我不想让producer类负责用户界面。我试图找出MVC的方式——视图处理获取动态信息,然后以某种方式将其传递给制作人。既然我在打字时仔细考虑了这一点,也许CDI事件就是我要做的事情?producer类观察事件,并在producer类中设置生成EntityManager时使用的动态数据?当数据库更改时,注入点将如何更新?如果db属性来自最终用户界面(我希望它不是公共界面:sql注入…)>“实际上JPA规范是EJB规范的一部分,只有规范文档是分开的”-您认为这是为什么?JPA只是JavaEE5/EJB3.0中EJB规范的一部分。它通过JSR317在JavaEE6/EJB3.1中成为自己的规范。看见