2014-09-30 93 views
2

我想弄清楚如何處理CDI。我正在研究一個用戶可以連接到多個數據庫的應用程序。應用程序詢問他們想要連接到哪一個,並且它們也可以斷開並連接到不同的數據庫。這是一個使用Seam for CDI和Hibernate for JPA的Java SE應用程序。我試圖弄清楚的是,如何利用CDI來連接@PersistenceContext,同時使它動態變化,以便訪問不同的數據庫。我只是不確定我會用CDI做這種模式或技術。思考?CDI根據用戶輸入注入@PersistenceContext

回答

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的代碼還有一些,但不是太多。

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,因此您可以使用Interceptors根據需要開始/檢查事務狀態並進行回滾/提交。

@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 } 
    } 
} 
+0

> PersistenceContext由EJB容器處理 - 這是不正確的。 JPA是EJB的一個獨立規範,持久化上下文通常由JPA實現的Java EE容器特定部分設置。 – 2014-09-30 07:04:13

+0

@ArjanTijms實際上JPA規範是EJB規範的一部分,只有規範文檔是分開的 – maress 2014-09-30 07:09:16

+0

我不清楚如何實現您評論的部分爲「//根據動態屬性在這裏加載EMF」我不想要生產者類負責用戶界面。我試圖找出MVC的方式 - 該視圖處理獲取動態信息然後以某種方式將其傳遞給製作人。現在我在打字的時候正在考慮這個問題,也許CDI活動是要走的路?生產者類觀察一個事件並在生成EntityManager時使用的生產者類中設置動態數據?數據庫更改時注入點如何更新? – 2014-09-30 15:22:56