23

我是 J(2)EE 和 Web 应用程序开发领域的新手,但我很快就在它周围导航并学到了很多东西。每一天对我来说都是一次奇妙的新发现之旅。

我目前正在做一个项目,我在 Glassfish v2 上使用 Visual JSF Woodstock。我对 JSF 也很陌生。

有时我需要在请求之间保存一些对象(例如 MyObject)。从我到目前为止所阅读和理解的内容来看,我需要使用会话在不同请求之间保存这些对象。到现在为止还挺好。

究竟如何做到这一点是我关心的地方。我知道在 JSP 中,您可以使用session.setAttribute("myObj", myObject)cookie 或 url 重写或隐藏表单变量将对象保存在客户端。

另一方面,在 JSF 中,我使用 Session 范围的 bean,例如 SessionBean1,并将对象保存为 SessionBean1 属性(例如SessionBean1.setSomeOjb(myObj))。这是解决这个问题的正确方法吗?

我猜测这样做会导致服务器端的内存利用率增加,因为每个请求都会创建会话范围 bean 的新实例 SessionBean1 以及 SessionBean1 中保存的 myObject 实例使用的内存。

我读过你可以使用FacesContext.getExternalContext().getSession/getSessionMap()它将在客户端保存会话变量。

那么您建议我使用哪种方法 - 会话范围的 bean 或 sessionmap 来保存对象以便在会话请求之间进行访问?

谢谢。

4

3 回答 3

24

一般来说,Java EE Web 应用程序往往不希望在客户端保存会话数据。您担心服务器端的会话膨胀是对的,一个常见的问题是会话占用量很大,这可能会导致严重的资源和性能问题,尤其是在集群环境中。

我想知道你在哪里看到

我已经读到您可以使用 FacesContext.getExternalContext().getSession/getSessionMap() 将会话变量保存在客户端。

我相信(在这一点上纠正我)这只是提供对 HttpSession 对象的访问权限,然后您可以在该对象上使用相同的

 session.setAttribute("myObj", myObject)

这本身并不会将对象发送回客户端,它保存在服务器中并由一些会话标识符作为键,通常在 cookie 中传递。

现在还有另外两种技术:您可以明确选择将数据放入您自己制造的 cookie 中——您可以从 JSF 或 JSP 访问的 servlet API 可以让您这样做,或者您可以在表单上使用隐藏字段,以及因此传递 aorund 会话数据。

但是考虑一下。我使用的 App Server 的经验法则是 1k-4k 数量级的 HttpSession 往往不是问题。比这更大(我已经看到以兆字节为单位的会话)确实对基础设施造成了压力。如果您担心这种大小的会话,您是否希望在每次请求时将 cookie 或隐藏字段中的兆字节数据发送回浏览器?即使是1k-2k,也可能有点大。

所以建议:

  1. 把事情简单化。使用 Session API 或其 JSF 表现形式。

  2. 控制会话中的数据量。

为回答有关集群的问题而添加:

通常,在集群环境中,我们具有会话亲和性,因此请求被发送回同一个集群成员。但是,当请求转到不同的服务器时,我们仍然需要考虑这种情况(也许如果集群成员失败)。

一些 App Server 供应商提供会话复制,或者通过直接的服务器间通信或通过将会话持久保存到数据库 - 显然这里有开销,所以有时,对于低价值会话,我们只接受在发生故障时会话丢失。

有一种说法是,如果会话数据具有很高的价值,那么它应该由应用程序持久化,它实际上是业务数据,应该这样对待。越来越多的 NOSQL 数据库(如 Cloudant 或 MongoDb)用于此目的。在这种情况下,我们可以将 HTTP 会话视为缓存,因为知道在发生错误时可以检索会话数据。

所以我认为购物车可能对企业具有相当大的价值。它代表了客户对他们想花钱的东西的深思熟虑的积累。所以它应该被持久化,而不是仅仅保留在会话中。一旦我们决定坚持它,我们就会发现它会导致其他有趣的场景,例如跨许多客户端设备的整合体验。客户开始在家中使用台式 PC 购物,但在线完成购买。

所以还有一个原则:

3)。不要仅仅因为它存在就过度使用 HTTP 会话。考虑数据的商业价值以及是否应该持久化。

于 2009-08-15T16:49:09.060 回答
15

我正在和我的同事一起研究大学的一个项目,是一个像 GoogleImage Labeler 这样的网络。好吧,所以我们有一个 UserController,它的方法有 login、logout 等......我们的 session 范围是这样的:

@ManagedBean(name = "userController")
@SessionScoped

好的,这就是 NetBeans 向导为您创建的内容。

我们创建和管理会话的方式是:

register 方法中(我们在 XHTML 中使用表单的属性...),我们将用户保存在 DB 中,然后我们在会话中添加值:

FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getSessionMap().put("user", current);

其中“当前”是一个用户(当然是登录的用户)。我们在登录方法上也是一样的。

注销方法中,我们有:

FacesContext.getCurrentInstance().getExternalContext().invalidateSession();

我希望这可以帮助你。

于 2011-11-17T13:11:16.357 回答
2

那么您建议我使用哪种方法 - 会话范围的 bean 或 sessionmap 来保存对象以便在会话请求之间进行访问?

这两件事将数据存储在完全相同的位置。

<managed-bean>
  <managed-bean-class>foo.Bar</managed-bean-class>
  <managed-bean-name>bar</managed-bean-name>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

一旦在表达式中引用,您可以通过外部上下文以编程方式查找“栏” 。

仅供参考:在 JSF2 中,可以删除声明并用注释替换:

@ManagedBean(name="bar") @SessionScoped
public class Bar {
...
于 2009-08-15T19:38:44.150 回答