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。 因为?无论如何,ServletContext
和 HttpSession
是 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的主要内容,如果未能解决你的问题,请参考以下文章
JavaEE基础(04):会话跟踪技术,Session和Cookie详解