我最终找到了一种解决方法,它可以让我获得@Stateful
bean 的引用:
我创建了一个@Named @Singleton @Startup
bean 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);
}
}
我从每个 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);
}
注意.getSession(true)
which 是必需的,因为 Session 可能尚未创建。另请注意,由于不是构造函数,this
因此已安全传递...@PostConstruct
毕竟,我可以像这样在我的 EntityListener (和任何其他地方)中获得参考:
SessionController sc = (SessionController) new InitialContext().lookup("java:module/SessionController");
UserSession us = sc.getCurrentUserSession();
或者像这样在 CDI bean 中
@Inject SessionController sc;
我看到的唯一缺点是这种方法仅适用于 Web 应用程序(FacesContext context = FacesContext.getCurrentInstance()
有意义的地方)。@javax.jws.WebService
我的一些 bean(最后是我的 EntityListeners)也通过@Stateless
bean 公开。在这种情况下(实际上:没有),我的 Singleton 将无法工作(尚未测试),因为没有任何类型的sessionId(确切地说根本没有会话)。我将不得不为此使用一种解决方法,可能使用 bean 的 SessionContext 或发明某种可用的sessionId。如果我创造了一些有用的东西,我会回帖......