我是J(2)EE和Web应用程序开发世界的新手,但我很快就在我身边学习并学习了很多东西。对我来说,每一天都是新发现的奇妙之旅。
我目前正在开发一个项目,我在Glassfish v2上使用Visual JSF Woodstock。我对JSF也很陌生。
有时我需要在请求之间保存一些对象(例如MyObject)。从我到目前为止所阅读和理解的内容来看,我需要使用会话来在不同请求之间保存这些对象。到目前为止一切都很好。
究竟如何做到这一点是我担心的地方。我知道在JSP中你可以使用session.setAttribute("myObj", myObject)
来保存客户端的对象,使用cookie或url重写或隐藏的表单变量。
另一方面,在JSF中,我使用Session scoped bean,比如说SessionBean1,并将对象保存为SessionBean1属性(例如SessionBean1.setSomeOjb(myObj)
)。这是正确的方法吗?
我猜这样做会导致服务器端的内存利用率增加,因为每个请求都会创建会话范围bean的新实例,SessionBean1加上SessionBean1中保存的myObject实例使用的内存。
我已经读过你可以使用FacesContext.getExternalContext().getSession/getSessionMap()
来保存客户端的会话变量。
那么您建议我使用哪种方法 - 会话范围bean或会话映射来保存对象以便在会话请求之间进行访问?
感谢。
答案 0 :(得分:21)
通常,Java EE Web Apps往往不希望保存会话数据客户端。你担心服务器端的会话膨胀是正确的,常见的问题是会有巨大的会话占用空间,这可能会导致严重的资源和性能问题,尤其是在集群环境中。
我想知道你在哪里看
我已经读过你可以使用FacesContext.getExternalContext()。getSession / getSessionMap()来保存客户端的会话变量。
我相信(在这一点上纠正我),这只是访问HttpSession对象,然后您可以使用相同的
session.setAttribute("myObj", myObject)
这本身并不将对象发送回客户端,它保存在服务器中并由某个会话标识符键入,通常在cookie中传递。
现在还有另外两种技术:您可以明确选择将数据放入您自己制造的cookie中 - 您可以从JSF或JSP访问的servlet API可以让您这样做,或者您可以使用隐藏字段形式,因此传递aorund会话数据。
但考虑一下。我使用的App Server的经验法则是1k-4k量级的HttpSession不会成为问题。比那更大(我已经看到以兆字节为单位的会话)会给基础设施带来压力。如果您担心该大小的会话,您是否希望在每次请求时将cookie或隐藏字段中的兆字节数据发送回浏览器?即使1k-2k也可能有点大。
所以建议:
保持简单。使用Session API或其JSF表现形式。
保持会话中的数据量受到控制。
在回答关于群集的问题时添加:
通常,在群集环境中,我们具有会话亲缘关系,以便将请求发送回同一群集成员。但是,当请求转到另一台服务器时,我们仍需要考虑这种情况(可能是一个集群成员失败)。
某些App Server供应商通过直接的服务器间通信或通过将会话持久保存到数据库来提供会话复制 - 显然这里存在开销,因此有时候,对于低价值会话,我们只接受会话丢失失败。
有一种观点认为,如果会话数据具有较高的值,那么它应该由应用程序保留,它实际上是业务数据,应该这样对待。越来越多地使用NantQL数据库,例如Cloudant或MongoDb。在这种情况下,我们可以将HTTP会话视为缓存,知道在发生错误时可以检索会话数据。
所以我认为购物车可能对业务有相当大的价值;它代表了客户对他们想要花钱的东西的深思熟虑的积累。因此它应该被持久化,而不是仅仅保留在会话中。一旦我们决定坚持下去,我们就会发现它会导致其他有趣的场景,例如跨多个客户端设备的整合体验。客户开始在家用桌面PC购物,但在线完成购买。
另一个原则是:
3)。不要因为它在那里而过度使用HTTP会话。考虑数据的业务价值以及是否应该保留数据。
答案 1 :(得分:14)
我和同事一起在大学开展项目,像GoogleImage Labeler这样的网络。 好吧,所以我们有一个UserController,它的方法是login,logout等...我们的会话范围如下:
@ManagedBean(name = "userController")
@SessionScoped
好的,这就是NetBeans向导为您创建的内容。
我们创建和管理会话的方式是:
在注册方法(我们在其中使用XHTML中表单的属性...)中,我们将用户保留在数据库中,然后我们在会话中添加值:
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getSessionMap().put("user", current);
“当前”是用户(当然是登录用户)。 我们在登录方法中也有相同的内容。
在退出方法,我们有:
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
我希望这会对你有所帮助。
答案 2 :(得分:2)
那么您建议我使用哪种方法 - 会话范围bean或会话映射来保存对象以便在会话请求之间进行访问?
这两件事将数据存储在完全相同的位置。
<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>
在表达式中引用后,您可以通过external context以编程方式查找“bar”。
仅供参考:在JSF2中,可以删除声明并替换为注释:
@ManagedBean(name="bar") @SessionScoped
public class Bar {
...