简体   繁体   English

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

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

I have a number of servlets that I'm rewriting from using PersistenceContext to using @Injected DAOs. 从使用PersistenceContext到使用@Injected DAO,我重写了许多servlet。

In JSF I could grab a reference to the FacesContext in my @Produces method and return the correct EM based on the logged in user (or use a default if logged in, valid user was available). 在JSF中,我可以在@Produces方法中获取对FacesContext的引用,并根据已登录用户返回正确的EM(或者如果已登录,则使用默认值,表明有效用户可用)。

How do I do this in a clean way when I have to produce different EMs for the same DAOs that are injected into different servlets and where the EM to be injected is dependent on the Servlet who started the "injection chain"? 当我必须为注入到不同servlet中的同一DAO生成不同的EM,并且要注入的EM取决于启动“注入链”的Servlet时,如何以一种干净的方式执行此操作?

Expected outcome: 预期结果:

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

Edit: 编辑:

I technically can get away with something like this I think but it is a huge mess when the DAOs are used otherwise as well and there are number of servlets to upgrade: 从技术上讲,我可以避免这样的事情,但是当同时使用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);
}

I assume that when you want to decide in servlet, your DAOs are supposed to use the same entity manager through whole request, as requests start and end in a servlet. 我假设当您要在Servlet中进行决策时,您的DAO应该在整个请求中使用相同的实体管理器,因为请求在Servlet中开始和结束。 In other words, while serving a http request, only one entity manager should be used. 换句话说,在处理http请求时,应仅使用一个实体管理器。

In this case, you may use built-in request scope and CDI event mechanism . 在这种情况下,您可以使用内置的请求范围和CDI事件机制 Create a producer for EM, which is request scoped, so that it is recreated each time with a new request. 请求的作用域创建EM的生产器,以便每次使用新请求重新创建它。 Then you may fire an event with particular entityManager as parameter, which is observed by your producer. 然后,您可以使用特定的entityManager作为参数来触发事件,生产者将观察到该事件。 When the event is received by the producer, it will store the EM and return it as produced value. 生产者收到事件后,它将存储EM并将其作为生产价值返回。

Schema of execution: 执行方案:

  1. appropriate EntityManager em is injected into servlet 适当的EntityManager em被注入到servlet中
  2. A CDI event emEvent is injected into the servlet 一个CDI事件emEvent被注入到servlet中
  3. either in @PostConstruct or at the beginning of serving method, fire the event by emEvent.fire(em) @PostConstruct或在服务方法的开头,通过emEvent.fire(em)触发事件
  4. EM producer with request scope observes events of type EntityManager, when received, stores the em 具有请求范围的EM生产者在收到时观察EntityManager类型的事件,将其存储
  5. all DAOs simply require injection of EntityManager 所有DAO都只需要注入EntityManager
    • producer returns stored instance EntityManager , received in the observed event 生产者返回在观察到的事件中接收到的存储实例EntityManager
  6. remember , that you must inject DAOs only after the event is fired, therefore all dependencies of the servlet, that rely on DAOs, must be injected dynamically using Instance , or must have a proxying scope (eg @RequestScoped , @SessionScoped ). 请记住 ,必须在事件触发后才注入DAO,因此,必须使用Instance动态注入依赖于DAO的servlet的所有依赖项,或者必须具有代理作用域(例如@SessionScoped @RequestScoped@SessionScoped )。 Otherwise the producer for the entity manager will be called before any event is received. 否则,将在接收到任何事件之前调用实体管理器的生产者。 But I believe that this also applies to your simple solution in your question. 但是我相信这也适用于您问题中的简单解决方案。

Code example: 代码示例:

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