我可以使用带有 CDI 的 EJB 无状态 Bean 来维护用户会话吗?

Posted

技术标签:

【中文标题】我可以使用带有 CDI 的 EJB 无状态 Bean 来维护用户会话吗?【英文标题】:Can I use EJB Stateless Bean with CDI to maintain user session? 【发布时间】:2011-09-13 19:14:17 【问题描述】:

基于这篇帖子http://www.adam-bien.com/roller/abien/entry/ejb_3_1_killed_the 我在我的应用程序中使用@Named @Stateless bean 与数据库进行通信(在此处注入 EntityManager)并在 jsf 页面上显示信息。自 Java EE 5 以来,这是一个很大的便利,但我有一个问题。

使用此类 bean 来维护用户会话(购物车等)是否安全?我读过一本关于 ejb 3.0 的书,我知道同一个无状态 bean 可以用于许多客户端。

使用具有所有 ejb 功能(事务、线程安全等)的托管 bean 的最佳方法是什么?我的意思是除了托管 bean + ejb 接口与 Java EE 5 中的实现 + ejb 注入之外的任何其他方式?

我使用 GlassFish 3.1 WebProfile

【问题讨论】:

感谢您的回答,那么我应该使用@Named @Stateful 还是 jsf 会话?哪个更好/更轻?当用户关闭浏览器和 ejb 会话时,jsf 会话结束? 或者也许将 ENtityManager 注入到 ManagedBean 中?安全吗? EJB 会话不一定会在用户关闭浏览器时结束,但 Web 用户以后将无法再次连接 EJB 会话。 EJB 代理通常保存在 http 会话、会话或视图范围内,当主 http 会话结束时,它们都会被销毁。 >或者也许将 EntityManager 注入到 ManagedBean 中? - 可能,但不如使用 EJB 方便,因为在这种情况下您需要自己处理启动、提交或回滚事务。如果托管 bean 被注入实体管理器,它也应该 - 不 - 是会话范围的。您需要将数据(会话范围)与数据库操作分开。实体管理器通常不是线程安全的。 【参考方案1】:

补充duffymo的建议;使用有状态会话 bean 与使用 HTTP 会话相比,还有一些额外的注意事项。

HTTP 会话基本上具有类似地图的结构。它可直接用于会话中的所有线程(请求)。这使得操作多个项目成为相对不安全的操作。可以在会话本身上进行同步,但这是一个有风险的操作,可能会导致整个应用程序死锁。 HTTP 会话确实允许您声明事件侦听器,该事件侦听器会在对 http 会话进行任何类型的修改时触发。

Stateful session bean 当然有一个 bean 结构。它具有一种自动同步功能,因为只有线程可以同时在 bean 中处于活动状态。通过注解,您可以声明其他线程是否等待(如果等待,等待多长时间)或在面对并发访问时立即抛出异常。

在每个用户通常只有一个 http 会话的情况下,单个用户可以同时使用多个有状态会话 bean。有状态会话 bean 的一个特别优点是它们有一种机制可以在超时后钝化它们的状态,这可以释放服务器的内存(当然是以磁盘空间为代价的)。有状态会话 bean 不直接具有 http 会话所具有的那种事件侦听器。

我认为最初有状态会话 bean 的“会话”方面是维护与远程非 Web 客户端(Swing、另一个 AS 等)的会话。这很像为维护与远程 Web 客户端的会话而创建的 http 会话。由于非 Web 客户端可以为有状态会话 bean 请求并保留多个代理,因此 Web 类比实际上更类似于最近引入的 conversation scope

在远程 Web 客户端与服务器通信的情况下,服务器在内部与有状态会话 bean 通信,这些概念非常重叠。远程 Web 客户端只知道 http 会话(通过 JSESSIONID),而对有状态会话 bean 的会话一无所知。因此,如果 http 会话丢失,您通常将无法再次将远程客户端与特定的有状态会话 bean 连接。因此,在这种情况下,HTTP 会话始终处于领先地位,您不妨将购物车项目存储在单个 (http) 会话范围的 bean 中。

有一种特殊情况,有状态会话 bean 可以在内部通信中派上用场,那就是如果您需要 JPA 的 extended persistence context。这可以用于例如实体上的锁定需要在请求之间持续(如果您的库存有限并且不想在用户实际结账时立即用“缺货”消息面对用户,这对于购物车来说可能很方便)。

【讨论】:

【参考方案2】:

无状态 bean 无法维护购物车或会话;这就是“无国籍”的意思。

您需要有状态的 EJB 或在 Web 层中进行。这些是唯一保持会话的地方。

【讨论】:

以上是关于我可以使用带有 CDI 的 EJB 无状态 Bean 来维护用户会话吗?的主要内容,如果未能解决你的问题,请参考以下文章

我是不是还需要在 CDI bean 上使用 EJB @Clustered 来进行分布式应用程序

EJB 的 CDI 生产者

JSF、CDI 和 EJB 容器:应该使用它们的哪种组合?

CDI 和 EJB 如何比较?相互作用?

在较新版本的 JSF 中,@FacesValidator 和 @FacesConverter 中的 EJB 和 CDI 注入点无法通过 OmniFaces 工作

EJB3 事务回滚