Java:跟踪用户登录会话 - 会话 EJB 与 HTTPSession

Posted

技术标签:

【中文标题】Java:跟踪用户登录会话 - 会话 EJB 与 HTTPSession【英文标题】:Java: Tracking a user login session - Session EJBs vs HTTPSession 【发布时间】:2011-02-18 00:32:30 【问题描述】:

如果我想使用我的 Web 应用程序跟踪每个客户端的会话状态,使用哪个更好的选择 - 会话 Bean 或 HTTP 会话?

使用 HTTP 会话:

//request is a variable of the class javax.servlet.http.HttpServletRequest
//UserState is a POJO
HttpSession session = request.getSession(true);
UserState state = (UserState)(session.getAttribute("UserState"));
if (state == null)  //create default value .. 
String uid = state.getUID();
//now do things with the user id

使用会话 EJB:

WEB-INF/web.xml注册为Web Application Listener的ServletContextListener实现中:

//UserState NOT a POJO this this time, it is
//the interface of the UserStateBean Stateful Session EJB
@EJB
private UserState userStateBean;

public void contextInitialized(ServletContextEvent sce) 
    ServletContext servletContext = sce.getServletContext();
    servletContext.setAttribute("UserState", userStateBean);
    ...

在 JSP 中:

public void jspInit() 
    UserState state = (UserState)(getServletContext().getAttribute("UserState"));
    ...

在同一 JSP 主体的其他地方:

String uid = state.getUID();
//now do things with the user id

在我看来,它们几乎相同,主要区别在于 UserState 实例在前者的 HttpRequest.HttpSession 中传输,而在后者的情况下则在 ServletContext 中传输。

这两种方法中哪一种更健壮,为什么?

【问题讨论】:

为什么要删除 servlets 标签?这与 servlet API 的关系比 EJB 是有状态的更相关。其实JSP标签也是无关紧要的。 @BalusC : Cos jsps 被编译成 servlet,实际上是一回事。另外,我的问题是关于有状态会话 EJB。 因为?无论如何,ServletContextHttpSession 是 Servlet API 的一部分,而不是 JSP API。您问题的根本原因正是在 Servlet API 中(实际上是对 Servlet API 的无知)。 【参考方案1】:

正如@BalusC 指出的那样,在您的示例中,所有客户端的 EJB 都是相同的——不是您想要的。

如果您在用户登录时创建 EJB 并将其存储在会话中或类似的东西中,您仍然可以更改它并为每个客户端拥有一个 EJB。

但是使用HttpSession 和有状态会话bean (SFSB) 之间还有其他更细微的区别。尤其是这两个:

    异常处理。如果 EJB 中的事务失败,则 bean 将失效并且不能再使用。这会使 Web 应用程序中的错误处理策略复杂化。 并发。不能同时访问同一个 SFSB,因此您需要在 Web 层中同步它。同样,这会使设计复杂化。

更多详情请查看此答案:Correct usage of SFSB with Servlets

总而言之:我建议您采用HttpSession 方法并反对SFSB;仅当 SFSB 提供了 HttpSession 无法提供的功能时才使用 SFSB,但事实并非如此。

【讨论】:

所以我在上面的代码中的错误是,为了让 Stateful Session EJB 成为每个客户端一个实例,我必须将它们存储在 HttpSession 而不是 ServletContext? 没错。会话范围正是为此目的。存储和跟踪特定于客户的信息。【参考方案2】:

澄清一点:ServletContext 在创建 servlet 时被初始化(参见 Servlet Specs),并且对于该实例来说是唯一的。 servlet 使用多个线程来处理并发的客户端请求。 servlet 容器决定何时创建或销毁 servlet 并委托客户端请求。

这就是为什么您最终可能有 1 个 servlet 处理 n 个用户 (n >= 1) 的请求,因此在上面使用 ServletContext 的示例代码中,每个用户最终都会共享导致创建的用户的会话 bean servlet。

【讨论】:

【参考方案3】:

ServletContext 代表应用范围。应用程序范围的属性在所有会话中的所有请求之间共享。它是“应用程序范围的全局变量”。您不想在其中存储客户端(因此,会话)特定信息。如果有新客户端登录,则应用程序范围内的现有 EJB 将被特定于客户端的 EJB 覆盖并反映给所有客户端。

会话范围正是为此目的。好好利用吧。

【讨论】:

会话 EJB 不存储每个客户端的会话状态吗?正如在一个会话 bean 实例中与一个客户端相关联,并且在会话期间保留特定于客户端的状态......或者我理解错了吗? 是的,确实如此。但是您每次都在应用程序范围内覆盖特定于客户端的 EJB。它适用于 1 个客户。但是对于多个客户端,last 客户端的 EJB 将被所有客户端使用。

以上是关于Java:跟踪用户登录会话 - 会话 EJB 与 HTTPSession的主要内容,如果未能解决你的问题,请参考以下文章

7Servlet会话跟踪

JavaEE基础(04):会话跟踪技术,Session和Cookie详解

Django之cookie与session

servlet 和 jsp 中的会话跟踪

我可以使用带有 CDI 的 EJB 无状态 Bean 来维护用户会话吗?

SIP 会话跟踪