看一下the unrelated portion of this answer to another question,虽然我理解为什么在问题的例子中对请求和响应的引用是线程安全的,为什么SessionScoped bean引用它绑定的HttpSession的线程是否安全?
@SessionScoped
public class SessionManager {
HttpSession session = null;
...
@PostConstruct void initialize() {
this.session = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
}
private void onLogin(@Observes @LoggedIn User user) {
// (1) housekeeping stuff
// (2) destroy older, duplicate login session, if user did not previously
// logout, in which case it would be really handy to have a reference
// to HttpSession.
}
}
答案 0 :(得分:2)
在实现上面概述的示例(参见OP)时,我意识到维护对会话的引用并不好,因为它确实是线程不安全的。这是臭臭的代码。
我很惊讶地看到旧会话不仅失效了,而且当前会话也被容器破坏了!因此,用户在两个浏览器中都已注销。后来,我遇到了this Websphere best practices documentation,虽然我没有使用Websphere,但是让我意识到缓存会话并不是一个好习惯:
避免尝试在每个servlet或JSP文件之外保存和重用HttpSession对象。
HttpSession对象是HttpRequest的函数(您只能通过req.getSession方法获取它),并且它的副本仅在servlet或JSP文件的服务方法的生命周期内有效。您无法缓存HttpSession对象并在servlet或JSP文件范围之外引用它。
无需缓存HttpSession;一个人可以改为缓存会话ID,当发现一个重复的会话时,只需将前一个重复会话的ID添加到Set<String> invalidatedLoginSessionIds.
然后重构应用程序,以便在收到旧会话的请求后立即使旧会话无效并重定向旧的浏览器到适当的facelet。如果没有收到这样的请求,那么旧的会话就会超时并且无论如何都要被销毁,所以不用担心。