从使用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 event mechanism。为请求的作用域创建EM的生产者,以便每次使用新请求重新创建它。然后,您可以使用特定的entityManager作为参数来触发事件,生产者将观察到该事件。生产者收到事件后,它将存储EM并将其作为生产价值返回。
执行方案:
将适当的EntityManager em
注入到servlet中
CDI事件emEvent
被注入到servlet中
在@PostConstruct
或服务方法开始时,通过emEvent.fire(em)
触发事件
具有请求范围的EM生产者在收到时观察EntityManager类型的事件,将其存储
所有DAO只需注入EntityManager
生产者返回在观察到的事件中接收到的存储实例EntityManager
请记住,必须在事件触发后才注入DAO,因此,依赖DAO的servlet的所有依赖项都必须使用Instance动态注入,或者必须具有代理作用域(例如@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;
}
}
关于java - CDI:在“注入(inject)链”中生成正确的EntityManager的好方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33806448/