为什么不应该在逻辑中使用JSF的SessionScoped bean?

5
我正在使用JSF创建一个Java EE Web应用程序,其中包含购物车式的流程,因此我希望在多个页面上收集用户输入,然后对其进行操作。
我想使用EJB 3有状态会话bean来实现这一点,但我的研究表明,SFSB与客户端的http会话无关,因此我必须通过httpSession手动跟踪它,这里有一些附加问题...
1)为什么它被称为会话bean?据我所见,它与会话无关,我可以通过将pojo存储在会话中来实现相同的功能。
2)如果我要注入的只是这个SFSB的新实例,那么注入它的意义何在?我不如使用pojo?
所以回到主要问题,我看到JSF是一种表示技术,因此不应用于逻辑,但它似乎是收集用户输入的完美选择。
我可以将JSF会话范围bean设置为所有请求bean的托管属性,这意味着它被注入到它们中,但与SFSB不同,JSF托管的会话范围bean与http会话绑定,因此只要http会话未失效,就始终注入相同的实例。
因此,我有多个层次:
第一层)处理演示文稿的JSF托管请求范围bean,每个页面1个。 第二层)JSF托管的会话范围bean,由请求bean设置值。 第三层)无状态会话EJB,在JSF会话范围bean中执行数据逻辑。
这样做有什么问题吗?
另一种选择是使用SFSB,但然后我必须在我的初始请求bean中注入它,然后将其存储在http会话中,并在每个后续请求bean中重新获取它-似乎很混乱。
或者我可以只将所有内容存储在会话中,但这不是理想的,因为它涉及使用文字键和转换等,容易出错。任何想法都会受到赞赏,我觉得我正在与这项技术作斗争,而不是与之合作。
谢谢
3个回答

9

为什么称之为会话bean,据我所见它与会话无关,通过将POJO存储在会话中也可以达到相同的效果。

来自旧版J2EE 1.3教程

什么是会话Bean?

会话Bean代表J2EE服务器内的单个客户端。客户端调用会话Bean的方法来访问部署在服务器上的应用程序。会话Bean为其客户端执行工作,通过在服务器内执行业务任务来保护客户端免受复杂性的影响。

顾名思义,会话Bean类似于交互式会话。会话Bean不是共享的-它可能只有一个客户端,就像交互式会话可能只有一个用户一样。像交互式会话一样,会话Bean不是持久的(即,其数据不保存到数据库中)。当客户端终止时,其会话Bean似乎终止并不再与客户端相关联。

因此,它与“会话”有关。但是,会话不一定意味着“HTTP会话”

如果我只注入一个新的SFSB实例,那注入它的意义是什么?我不如使用POJO呢?
首先,你不能在无状态组件中注入SFSB(在另一个SFSB中注入是可以的),你必须进行查找。其次,在HTTP会话和SFSB之间选择取决于您的应用程序和需求。从纯理论角度来看,HTTP会话应该用于表示逻辑状态(例如,多页面表单中的当前位置),而SFSB应该用于业务逻辑状态。这在TSS上的“旧”HttpSession v.s. Stateful session beans线程中得到了很好的解释,其中还有一个很好的示例,说明何时使用SFSB是有意义的:
您可能想使用有状态会话Bean来跟踪特定事务的状态,例如某人购买火车票。Web会话跟踪用户在html页面流程中的状态。但是,如果用户通过不同的渠道访问系统(例如WAP手机或呼叫中心),您仍然需要知道购票交易的状态。
但是,SFSB并不简单,如果您没有需要证明其使用价值的需求,我的实际建议是坚持使用HTTP会话(特别是如果这对您来说都是新的)。以防万一,请参见:
- 无状态和有状态企业Java Bean - Web应用程序中的有状态EJB? 因此,回到主要问题,我发现JSF是一种表示技术,因此不应用于逻辑,但它似乎是收集用户输入的完美选择。

这不是业务逻辑,而是展示逻辑。

所以我有多个层次 (...)

不,你可能有一个客户端层、一个展示层、一个业务层和一个数据层。你描述的更像是层级(甚至不确定)。参见:

为什么这样不好?

我不知道,我不知道你在说什么 :) 但你可能只需将多个页面表单信息收集到 SessionScoped bean 中,并在流程结束时调用 Stateless Session Bean (SLSB)。


谢谢Pascal,你的回答非常清晰,解答了我所有的问题,干杯! - PiersyP
2
实际上,这是关键词语 -“那不是业务逻辑,而是表示逻辑”- 这是一句重要的引言。 - PiersyP

6

1) 为什么叫会话Bean,我看它似乎与会话无关,我可以通过在会话中存储POJO来实现相同的功能。

更正:EJB会话与HTTP会话无关。在EJB中,客户端是servlet容器,服务器是EJB容器(两者都在Web /应用程序服务器上运行)。在HTTP中,客户端是Web浏览器,服务器是Web /应用程序服务器。

现在有意义了吗?

2) 如果我只注入此SFSB的新实例,那注入它有什么意义呢?我可能还不如使用POJO?

使用EJB进行事务性业务任务。使用作用域为会话的托管bean来存储HTTP会话特定数据。顺便说一下,这两个都不是POJO,只是Java Bean。

为什么不应该在JSF SessionScoped bean中使用逻辑?

如果您没有利用事务性业务任务和EJB提供的抽象,则在简单的JSF托管bean中执行操作确实不是一个坏的选择。这也是基本JSF应用程序的常规方法。然而,动作通常应在请求范围的托管bean中执行,其中会话范围的bean被注入为@ManagedProperty

但是,既然您已经在使用EJB了,我会质疑是否没有使用EJB的特定原因。如果这是来自上层的业务要求,那么我会坚持使用它。至少,您的会话混淆现在应该已经清除了。


感谢您的快速回复。仍然感到困惑,您说SFSB与http会话无关,它们与哪种会话有关?而无状态会话bean似乎命名更容易引起误解,当没有状态时,它们怎么可能属于任何类型的会话?2)谢谢解释,我不需要执行事务业务任务,所以将使用会话作用域托管bean。我的观点是,我的会话作用域托管bean只是保存数据而不执行任何演示任务,但从您所说的来看,这不是一个坏选择。 - PiersyP
状态与业务逻辑相关。我建议阅读ewernli关于SLSB vs SFSB的优秀回答:http://stackoverflow.com/questions/3099699/can-we-use-both-stateless-and-stateful-session-beans-in-a-j2ee-application/3099823#3099823 和 https://dev59.com/03E85IYBdhLWcg3wXCS1#2811833 - BalusC

2

如果您不知道这一点,作为对您已有答案的小贡献,您确实可以使用 @SessionScoped 注释一个 SFSB,CDI 将处理 EJB 的生命周期...这将将 EJB 绑定到 CDI 管理的 Http 会话。告诉您这个消息,因为您在问题中提到:

but my research leads me to believe that a SFSB is not tied to a client's http session, so I would have to manually keep track of it via an httpSession, some side questions here . . .

此外,您可以按照自己的想法去做,但这取决于您的要求。在 CDI bean 获得声明式事务支持或扩展持久性上下文等方面之前,您会发现自己需要编写很多样板代码,这会使您的 bean 不够清晰简洁。当然,您也可以使用像 Seam(现在转移到 DeltaSpike)这样的框架,通过它们的扩展增强 bean 的某些功能。

所以,我认为,乍一看,您可能觉得使用有状态的 EJB 是不必要的,但某些用例可能更适合通过它们来解决。如果一个用户将产品添加到购物车中,另一个用户稍后添加了相同的产品,但库存只有一个单位,谁会得到它?结账更快的那个人还是先添加的那个人?如果您想访问实体管理器以在用户随意关闭浏览器时将 kart 持久化,或者如果您有跨多个页面生成事务并希望每一步都同步到数据库的事务,该怎么办?(长时间保持事务不推荐,但也许有场景需要这样做?)您可以使用 SLSB,但有时使用 SFSB 更好、更清晰。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接