Java CDI:在一个“系统”中生成正确的EntityManager的好方法;注射链“;

Java CDI:在一个“系统”中生成正确的EntityManager的好方法;注射链“;,java,jakarta-ee,servlets,cdi,java-ee-6,Java,Jakarta Ee,Servlets,Cdi,Java Ee 6,我有很多servlet,我正在重写它们,从使用PersistenceContext改为使用@inspectedaos 在JSF中,我可以在@products方法中获取对FacesContext的引用,并根据登录用户返回正确的EM(如果登录,则使用默认值,有效用户可用) 当我必须为注入到不同Servlet中的相同DAO生成不同的EMs,并且要注入的EM依赖于启动“注入链”的Servlet时,如何以干净的方式做到这一点 预期成果: Servlet 1 DaoA

我有很多servlet,我正在重写它们,从使用PersistenceContext改为使用@inspectedaos

在JSF中,我可以在@products方法中获取对FacesContext的引用,并根据登录用户返回正确的EM(如果登录,则使用默认值,有效用户可用)

当我必须为注入到不同Servlet中的相同DAO生成不同的EMs,并且要注入的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   |            |           |
+-----------+            +-----------+            +-----------+

我假设当您想在servlet中做出决定时,DAO应该在整个请求中使用相同的实体管理器,因为请求在servlet中开始和结束。换句话说,在服务http请求时,只应使用一个实体管理器

在这种情况下,您可以使用内置的请求作用域和。为EM创建一个producer,该producer的作用域为request,以便每次都使用新请求重新创建它。然后,您可以使用特定的entityManager作为参数触发事件,该参数由您的生产者观察。当生产者接收到事件时,它将存储EM并将其作为生产值返回

执行模式:

  • 将适当的
    EntityManager em
    注入servlet
  • CDI事件
    emEvent
    被注入servlet
  • @PostConstruct
    中或在服务方法开始时,通过
    emEvent.fire(em)
  • 具有请求作用域的EM producer观察EntityManager类型的事件,收到时存储EM
  • 所有DAO只需要注入
    EntityManager
    • 生产者返回在观察到的事件中接收到的存储实例
      EntityManager
  • 请记住,您必须仅在触发事件后注入DAO,因此依赖DAO的servlet的所有依赖项必须使用动态注入,或者必须具有代理作用域(例如
    @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 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;
      }
    }