3

看看另一个问题的答案的不相关部分,虽然我理解为什么在问题的示例中对请求和响应的引用是线程不安全的,为什么 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. 

    }
}
4

1 回答 1

2

在实现我在上面勾勒出的示例时(请参阅 OP),我意识到维护对会话的引用并不好,因为它确实是线程不安全的。这是臭代码。

我惊讶地发现不仅旧会话无效,而且当前会话也被容器破坏了!因此,用户在两个浏览器中都已注销。后来,我遇到了这个 Websphere 最佳实践文档,虽然我没有使用 Websphere,但它帮助我意识到缓存会话根本不是一个好的实践:

避免尝试在每个 servlet 或 JSP 文件之外保存和重用 HttpSession 对象。

HttpSession 对象是 HttpRequest 的一个函数(只能通过 req.getSession 方法获取),它的副本只在 servlet 或 JSP 文件的 service 方法的生命周期内有效。您不能缓存 HttpSession 对象并在 servlet 或 JSP 文件范围之外引用它。

不需要缓存HttpSession;可以改为缓存会话 ID,当发现重复会话时,只需将前一个重复会话的 ID 添加到Set<String> invalidatedLoginSessionIds.然后重构应用程序,以便在收到来自旧会话的请求后立即使旧会话无效并将旧浏览器重定向到适当的 facelet . 如果没有收到这样的请求,旧会话将简单地超时并被销毁,所以不用担心。

于 2013-01-29T19:07:33.220 回答