簡體   English   中英

CDI:在“注入鏈”中生成正確的EntityManager的好方法

[英]CDI: Good way to produce correct EntityManager in an “Injection chain”

從使用PersistenceContext到使用@Injected DAO,我重寫了許多servlet。

在JSF中,我可以在@Produces方法中獲取對FacesContext的引用,並根據已登錄用戶返回正確的EM(或者如果已登錄,則使用默認值,表明有效用戶可用)。

當我必須為注入到不同servlet中的同一DAO生成不同的EM,並且要注入的EM取決於啟動“注入鏈”的Servlet時,如何以一種干凈的方式執行此操作?

預期結果:

  Servlet 1                 DaoA                   EntityM. x
+-----------+            +-----------+            +-----------+
| @Inject   | Inject into|  @Inject  | Inject into|           |
| DaoA daoA <-----+------+  E.M. em  <------------+           |
| etc       |     |      |  //em x   |            |           |
+-----------+     |      +-----------+            +-----------+
                  |         DaoB                   EntityM. x
                  |      +-----------+            +-----------+
                  |      |  @Inject  | Inject into|           |
                  +------+  E.M. em  <------------+           |
                         |  //em x   |            |           |
                         +-----------+            +-----------+

  Servlet 2                 DaoA                   EntityM. y
+-----------+            +-----------+            +-----------+
| @Inject   | Inject into|  @Inject  | Inject into|           |
| DaoA daoA <------------+  E.M. em  <------------+           |
|           |            |  //em y   |            |           |
+-----------+            +-----------+            +-----------+

編輯:

從技術上講,我可以避免這樣的事情,但是當同時使用DAO且有許多servlet需要升級時,這很麻煩。

//In Servlet 1
@PersistenceContext(unitName="x")
EntityManager em;

@Inject
DaoA daoA;

@Inject
DaoB daoB;

@Postconstruct
public void postConstruct() {
  daoA.setEm(em);
  daoB.setEm(em);
}

//In Servlet 2
@PersistenceContext(unitName="y")
EntityManage r em;

@Inject
DaoA daoA;

@Postconstruct
public void postConstruct() {
  daoA.setEm(em);
}

我假設當您要在Servlet中進行決策時,您的DAO應該在整個請求中使用相同的實體管理器,因為請求在Servlet中開始和結束。 換句話說,在處理http請求時,應僅使用一個實體管理器。

在這種情況下,您可以使用內置的請求范圍和CDI事件機制 請求的作用域創建EM的生產器,以便每次使用新請求重新創建它。 然后,您可以使用特定的entityManager作為參數來觸發事件,生產者將觀察到該事件。 生產者收到事件后,它將存儲EM並將其作為生產價值返回。

執行方案:

  1. 適當的EntityManager em被注入到servlet中
  2. 一個CDI事件emEvent被注入到servlet中
  3. @PostConstruct或在服務方法的開頭,通過emEvent.fire(em)觸發事件
  4. 具有請求范圍的EM生產者在收到時觀察EntityManager類型的事件,將其存儲
  5. 所有DAO都只需要注入EntityManager
    • 生產者返回在觀察到的事件中接收到的存儲實例EntityManager
  6. 請記住 ,必須在事件觸發后才注入DAO,因此,必須使用Instance動態注入依賴於DAO的servlet的所有依賴項,或者必須具有代理作用域(例如@SessionScoped @RequestScoped@SessionScoped )。 否則,將在接收到任何事件之前調用實體管理器的生產者。 但是我相信這也適用於您問題中的簡單解決方案。

代碼示例:

//In Servlet 1
@PersistenceContext(unitName="x")
EntityManager em;

@Inject
Event<EntityManager> emEvent;

@Inject
Instance<DaoA> daoAInstance;

@Postconstruct
public void postConstruct() {
  emEvent.fire(em);
  daoAInstance.get().find(...);  /* at this point, proper EM will be injected into DaoA. 
                 You should access daoA only after emEvent is fired*/
}

// in producer
@RequestScoped (producer will be recreated for every request)
public class DynamicEMProducer {

  EntityManager em; /* not injected, but set in observer method. 
        You may inject a default em if you wish using @PersistenceContext */

  // this is handler of event fired in the servlet
  public void emChanged(@Observes EntityManager em) {
    this.em = em;
  }

  @Produces
  public EntityManager produce() {
    return em;
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM