在EntityListener中注入SessionScoped有状态bean

Cas*_*der 5 java ejb glassfish javabeans cdi

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

@EntityListeners在我的@MappedSuperclass实体上添加了一个注释,监听器在其方法上有注释@PrePersist@PreUpdate注释,这些注释在运行时被愉快地调用.

在这些方法中,我试图用(@Inject)一@Named,@Stateful,@SessionScoped豆(UserSession为了获得当前用户的ID).监听器类根本没有注释.

问题是我无法UserSession注入豆子; 我总是最终得到一个null价值.到目前为止,我尝试了总是注入空值的plain .我@Inject UserSession us;也尝试过UserSession us = (UserSession) ctx.lookup("java:global/application/module/UserSession");总是返回一个新对象(我验证了构造函数调用,加上对象为).

我很确定我错过了一些关于CDI非常重要但我无法弄清楚是什么.有人可以指出我正确的方向吗?

Cas*_*der 1

我最终找到了一个解决方法,它允许我获得 bean 的引用@Stateful

我创建了一个@Named @Singleton @Startupbean SessionController,它保存了本地HashMap<String, UserSession> sessionMap的 bean 引用@Stateful

@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);
}
Run Code Online (Sandbox Code Playgroud)

}

我在每个 bean 的方法中添加引用@PostConstruct

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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,这.getSession(true)是必需的,因为会话可能尚未创建。另请注意,它this是安全传递的,因为它@PostConstruct不是构造函数......

所有这些之后,我可以在我的 EntityListener (以及任何其他地方)中获取引用,如下所示:

SessionController sc = (SessionController) new InitialContext().lookup("java:module/SessionController");
    UserSession us = sc.getCurrentUserSession();
Run Code Online (Sandbox Code Playgroud)

或者在 CDI 豆中像这样

@Inject SessionController sc;
Run Code Online (Sandbox Code Playgroud)

我看到的唯一缺点是这种方法仅适用于 Web 应用程序(有意义FacesContext context = FacesContext.getCurrentInstance())。我的一些 bean(最后是我的 EntityListener)也通过@javax.jws.WebServiceas @Statelessbeans 公开。在这种情况下(实际上:没有),我的单例将无法工作(尚未测试),因为没有任何类型的sessionId(确切地说根本没有会话)。我将不得不为此使用一种解决方法,可能使用 bean 的 SessionContext 或发明某种可用的sessionId 。如果我创建了一些可用的东西,我会回复...