在EntityListener中注入SessionScoped状态bean [英] Injecting a SessionScoped Stateful bean in EntityListener

查看:201
本文介绍了在EntityListener中注入SessionScoped状态bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在GlassFish 3上的Java EE JPA应用程序中实现某种审计。



我添加了一个 @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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆