为啥我不应该将 JSF SessionScoped bean 用于逻辑?

Posted

技术标签:

【中文标题】为啥我不应该将 JSF SessionScoped bean 用于逻辑?【英文标题】:Why shouldn't I use a JSF SessionScoped bean for logic?为什么我不应该将 JSF SessionScoped bean 用于逻辑? 【发布时间】:2011-04-07 11:07:15 【问题描述】:

我正在开发一个使用 JSF 和购物车样式流程的 Java EE Web 应用程序,因此我想收集多个页面上的用户输入,然后对其进行处理。

我正在考虑为此使用 EJB 3 有状态会话 bean,但我的研究使我相信 SFSB 不绑定到客户端的 http 会话,因此我必须通过 httpSession 手动跟踪它,这里有一些附带问题。 . .

1)为什么叫session bean,据我看和session没有关系,我可以通过在session中存储一个pojo来实现。

2) 能够注入它有什么意义,如果我要注入的只是这个 SFSB 的一个新实例,那么我还不如使用 pojo?

回到我看到的主要问题,JSF 是一种表示技术,所以它不应该用于逻辑,但它似乎是收集用户输入的完美选择。

我可以将 JSF 会话范围 bean 设置为我所有请求 bean 的托管属性,这意味着它被注入到它们中,但与 SFSB 不同的是,JSF 托管会话范围 bean 绑定到 http 会话,因此同一个实例是只要 http 会话没有失效,就会一直注入。

所以我有多层

第 1 层)JSF 管理的请求范围 bean,用于处理表示,每页 1 个。 第二层)一个 JSF 管理的会话范围 bean,其值由请求 bean 在其中设置。 第三层)一个无状态会话 EJB,它对 JSF 会话范围 bean 中的数据执行逻辑。

为什么会这么糟糕?

另一种选择是使用 SFSB,但我必须将其注入到我的初始请求 bean 中,然后将其存储在 http 会话中并在每个后续请求 bean 中重新获取它 - 看起来很混乱。

或者我可以将所有内容都存储在会话中,但这并不理想,因为它涉及使用文字键和强制转换。等..等容易出错。 . .又乱又乱!

任何想法都值得赞赏,我觉得我是在与这项技术作斗争,而不是在使用它。

谢谢

【问题讨论】:

【参考方案1】:

为什么叫 session bean,据我看和 session 没有关系,我可以通过在 session 中存储一个 pojo 来实现。

来自老J2EE 1.3 tutorial:

What Is a Session Bean?

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

顾名思义,会话 bean 类似于交互式会话。 会话 bean 不是共享的——它可能 只有一个客户,以同样的方式 交互式会话可能具有 只有一个用户。就像一个互动 会话,会话 bean 不是 执着的。 (也就是说,它的数据不是 保存到数据库中。)当客户端 终止,它的会话 bean 出现 终止,不再是 与客户相关联。

所以它与“会话”有关。但 session 不一定是指“HTTP session”

能够注入它有什么意义,如果我要注入的只是这个 SFSB 的一个新实例,那么我还不如使用 pojo?

嗯,首先,您不要在无状态组件中注入 SFSB(注入另一个 SFSB 就可以了),您必须进行查找。其次,在 HTTP 会话和 SFSB 之间进行选择实际上取决于您的应用程序和您的需求。从纯理论的角度来看,HTTP 会话应该用于表示逻辑状态(例如,您在多页表单中的位置),而 SFSB 应该用于业务逻辑状态。这在 TSS 上的“旧”HttpSession v.s. Stateful session beans 线程中得到了很好的解释,该线程也有一个很好的例子,说明 SFSB 是有意义的:

您可能想要使用有状态会话 bean 来跟踪一个状态 特定的交易。即某人 买火车票。

网络会话跟踪状态 用户在 html 页面中的位置 流动。但是,如果用户随后获得 通过访问系统 不同的频道,例如 wap 电话,或 通过呼叫中心,您仍然会 想知道票的状态 购买交易。

但 SFSB 并不简单,如果您不需要证明使用它们的合理性,我的实用建议是坚持使用 HTTP 会话(尤其是如果所有这些对您来说都是新的)。以防万一,请参阅:

Stateless and Stateful Enterprise Java Beans Stateful EJBs in web application?

回到我看到的主要问题,JSF 是一种表示技术,所以它不应该用于逻辑,但它似乎是收集用户输入的完美选择。

那不是业务逻辑,那是表示逻辑。

所以我有多层 (...)

没有。您可能有一个客户层、一个表示层、一个业务层、一个数据层。你所描述的看起来更像层(甚至不确定)。见:

Can anybody explain these words: Presentation Tier, Business Tier, Integration Tier in java EE with example? Spring, Hibernate, Java EE in the 3 Tier architecture

为什么会这么糟糕?

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

【讨论】:

谢谢帕斯卡,一个非常明确的答案回答了我所有的问题,干杯! 实际上这是关键短语 - “这不是业务逻辑,这是表示逻辑” - 一个主要的引述【参考方案2】:

1) 为什么叫session bean,据我看和session没有关系,我可以通过在session中存储一个pojo来达到同样的效果。

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

现在更有意义了吗?

2) 能够注入它有什么意义,如果我要注入的只是这个 SFSB 的一个新实例,那么我还不如使用 pojo?

将 EJB 用于事务性业务任务。使用会话范围的托管 bean 来存储 HTTP 会话特定的数据。顺便说一句,两者都不是POJO。只是 Javabeans。

为什么我不应该使用 JSF SessionScoped bean 来实现逻辑?

如果您没有从事务性业务任务和 EJB 围绕它提供的抽象中受益,那么仅在一个简单的 JSF 托管 bean 中执行它确实不是一个糟糕的选择。这也是基本 JSF 应用程序中的常规方法。然而,这些操作通常发生在请求范围的托管 bean 中,其中会话范围的托管 bean 被注入为@ManagedProperty

但既然您已经在使用 EJB,我会质疑是否没有使用 EJB 的特定原因。如果这是占上风的业务要求,那么我会坚持下去。至少,你的会话混乱现在应该被清除了。

【讨论】:

感谢您的快速回复。仍然感到困惑,您说 SFSB 与 http 会话无关,它们与什么样的会话有关,无状态会话 bean 呢,它们似乎更容易被误导,它们如何属于任何类型的会话是没有状态? 2)感谢清除不需要执行事务性业务任务,因此将使用会话范围的托管bean。我想我要说的一点是,我的会话范围托管 bean 只会保存数据而不执行任何演示任务,但从你所说的来看,这不是一个坏选择。 状态与业务逻辑有关。我建议阅读 ewernli 关于 SLSB 与 SFSB 的精彩答案:***.com/questions/3099699/… 和 ***.com/questions/2811312/…【参考方案3】:

以防万一您不知道这一点,并且作为对您的答案的一小部分贡献,您确实可以使用 @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,但通过它们可能会更好地解决某些用例。如果用户将产品添加到他的购物车中,而另一个用户稍后添加了相同的产品,但库存中只有一个单位,谁会得到它?结账速度更快的人?还是第一个添加它的人?如果您想访问您的实体管理器以在用户决定随机关闭他的浏览器的情况下持久保存卡丁车怎么办,或者如果您有生成多个页面的事务并且您希望每个步骤都同步到数据库怎么办? (不建议长时间保持交易开放,但可能存在需要这样做的情况?)您可以使用 SLSB,但有时使用 SFSB 更好更清洁..

【讨论】:

以上是关于为啥我不应该将 JSF SessionScoped bean 用于逻辑?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 f:validateDoubleRange 仅适用于 @SessionScoped?

为啥 JSF 将 UI 组件的状态保存在服务器上?

使用 URL 参数的 JSF 托管 Bean 方法调用

为啥我的 JSF 复合方面的验证在未呈现方面时完成

检查会话是不是存在 JSF

JSF 服务层