在EntityListener中注入SessionScoped状态bean [英] Injecting a SessionScoped Stateful bean in EntityListener
问题描述
我添加了一个 @EntityListeners @MappedSuperclass
实体中的注释,该侦听器具有 @PrePersist
和 @PreUpdate
在运行时快速调用的方法的注释。
在这些方法中,我试图使用( @Inject
)a @命名为
, @Stateful
, @SessionScoped
bean( UserSession
),以获取当前用户的ID。侦听器类根本没有注释。
问题是我无法获取注入的 UserSession
我总是得到一个 null
值。到目前为止,我尝试了 @Inject UserSession us;
,它总是注入一个空值。我也尝试过 UserSession us =(UserSession)ctx.lookup(java:global / application / module / UserSession);
它总是返回一个新对象(我验证了构造函数调用,加上对象是空
我很确定我错过了关于CDI的一些非常重要的事情,但我无法弄明白什么。有人可以指出我正确的方向吗?
我最终找到了一个解决方法,这让我得到一个 @Stateful
bean:
我创建了一个 @Named @Singleton @Startup
bean SessionController,其中包含一个本地 HashMap< String,UserSession> sessionMap
与我的 @Stateful
bean的引用:
@Named
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class SessionController {
private HashMap< String, UserSession> sessionMap;
@PostConstruct
void init(){
sessionMap = new HashMap< String,UserSession>();
}
@PreDestroy
void terminate(){
for(UserSession us:sessionMap.values()){
us.logoutCleanUp(); //这被注释为@Remove
}
sessionMap.clear();
}
public void addSession(String sessionId,UserSession us){
sessionMap.put(sessionId,us);
System.out.println(New Session added:+ sessionId);
}
public UserSession getCurrentUserSession(){
FacesContext context = FacesContext.getCurrentInstance();
String sessionId =((HttpSession)context.getExternalContext()。getSession(false))。getId();
return sessionMap.get(sessionId);
}
}
我从每个bean的 @PostConstruct
方法中添加引用:
public UserSession类实现Serializable {
@Inject SessionController sc;
...
@PostConstruct
void init(){
FacesContext context = FacesContext.getCurrentInstance();
String sessionId =((HttpSession)context.getExternalContext()。getSession(true))。getId();
sc.addSession(sessionId,this);
}
注意 .getSession(true)
这是必需的,因为会话可能尚未创建。还要注意,这个
是安全的,因为 @PostConstruct
不是构造函数...
所有这些之后,我可以在我的EntityListener(和任何其他地方)中获得这样的引用:
SessionController sc =(SessionController)new InitialContext()。lookup(java:module / SessionController);
UserSession us = sc.getCurrentUserSession();
或在CDI beans中这样
@Inject SessionController sc;
我看到的唯一缺点是这种方法只适用于Web应用程序(其中 FacesContext context = FacesContext.getCurrentInstance()
是有意义的)。我的一些bean(最后我的EntityListeners)也通过 @ javax.jws.WebService
作为 @Stateless
beans 。在这种情况下(实际上是缺少),我的Singleton将无法工作(尚未测试),因为没有任何类型的会话ID(/ em>)没有任何会话完全准确。我将不得不使用一个解决方法来解决这个问题,可能使用Bean的SessionContext或者发明某种可用的 sessionId 。如果我创造了一些可用的东西,我会发布回来。
I'm trying to implement some sort of auditing in a Java EE JPA application on GlassFish 3.
I have added a @EntityListeners
annotation on my @MappedSuperclass
entity, the listener has the @PrePersist
and @PreUpdate
annotation on its methods which are invoked happily at runtime.
In these methods, I'm trying to use (@Inject
) a @Named
, @Stateful
, @SessionScoped
bean (UserSession
) in order to get current user's id. The listener class has no annotations at all.
The problem is that I can't get the UserSession
bean injected; I always end up with a null
value. To this time, I tried the plain @Inject UserSession us;
which always injects a null value.I also tried UserSession us = (UserSession) ctx.lookup("java:global/application/module/UserSession");
which always returns a new object (I verified the constructor call, plus the object is empty).
I'm pretty sure I have missed something very important regarding CDI but I can't figure out what. Could someone please point me to the right direction?
I eventually found a workaround, which allows me to get a reference of the @Stateful
bean:
I created a @Named @Singleton @Startup
bean SessionController which holds a local HashMap<String, UserSession> sessionMap
with the references of my @Stateful
beans:
@Named
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class SessionController {
private HashMap<String, UserSession> sessionMap;
@PostConstruct
void init() {
sessionMap = new HashMap<String, UserSession>();
}
@PreDestroy
void terminate() {
for (UserSession us : sessionMap.values()) {
us.logoutCleanUp(); //This is annotated as @Remove
}
sessionMap.clear();
}
public void addSession(String sessionId, UserSession us) {
sessionMap.put(sessionId, us);
System.out.println("New Session added: " + sessionId);
}
public UserSession getCurrentUserSession() {
FacesContext context = FacesContext.getCurrentInstance();
String sessionId = ((HttpSession) context.getExternalContext().getSession(false)).getId();
return sessionMap.get(sessionId);
}
}
I add the references from within each bean's @PostConstruct
method:
public class UserSession implements Serializable {
@Inject SessionController sc;
...
@PostConstruct
void init() {
FacesContext context = FacesContext.getCurrentInstance();
String sessionId = ((HttpSession) context.getExternalContext().getSession(true)).getId();
sc.addSession(sessionId, this);
}
Notice the .getSession(true)
which is required since the Session might not be created yet. Also notice that this
is safely passed since the @PostConstruct
is not the constructor...
After all these, I can get the reference in my EntityListener (and any other place) like this:
SessionController sc = (SessionController) new InitialContext().lookup("java:module/SessionController");
UserSession us = sc.getCurrentUserSession();
or like this in CDI beans
@Inject SessionController sc;
The only drawback I see is that this approach works well only for web applications (where FacesContext context = FacesContext.getCurrentInstance()
is meaningful). Some of my beans (and finally my EntityListeners) are also exposed via @javax.jws.WebService
as @Stateless
beans. In this context (actually: absence of), my Singleton wouldn't work (haven't tested yet) since there is no sessionId of any kind (no session at all to be exact). I will have to use a workaround for this, possibly using SessionContext of the bean or inventing a usable sessionId of some sort. I will post back if I create something usable...
这篇关于在EntityListener中注入SessionScoped状态bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!