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

如果我想使用我的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 

使用Session EJB:

在ServletContextListener的实现中,在WEB-INF/web.xml注册为Web应用程序侦听器:

 //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中传输。

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

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

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

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

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

有关更多详细信息,请参阅此答案: 使用Servlet正确使用SFSB

总结:在你的情况下,我会建议采用HttpSession方法并针对SFSB; 只有当它提供了HttpSession无法做到的事情时才使用SFSB,但事实并非如此。

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

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

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

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