【问题标题】:Backing beans (@ManagedBean) or CDI Beans (@Named)?支持 bean (@ManagedBean) 还是 CDI Bean (@Named)?
【发布时间】:2013-03-03 02:49:20
【问题描述】:

我刚刚开始阅读Core JavaServer Faces, 3rd Ed.,他们这样说(强调我的):

有两个独立的机制,CDI bean 是历史性的偶然 和 JSF 托管 bean,用于可在 JSF 页面中使用的 bean。 我们建议 除非您的应用程序必须在普通 servlet 上运行,否则您使用 CDI bean 像Tomcat这样的运行器。

为什么?他们没有提供任何理由。我一直在为在 GlassFish 3 上运行的原型应用程序中的所有 bean 使用 @ManagedBean,但我并没有真正注意到任何问题。我并不特别介意从 @ManagedBean 迁移到 @Named,但我想知道我为什么要打扰

【问题讨论】:

  • @Bozho:这个问题非常相似,但是在阅读了 Pascal 的回答几次之后,我仍然不明白 为什么 CDI 远优于。 我不知道 CDI,我很高兴学习它,因为它“更好”。为什么更好?
  • “除非你的应用程序必须在普通的 servlet 运行程序上运行,例如 Tomcat”我只使用 tomcat,我强烈推荐 CDI。 Tomcat 支持就好了
  • @KarlKildén “plain servlet runner”指的是不支持 CDI 的 servlet 容器。在撰写本文时,Tomcat 不支持 CDI,除非使用了相当多的魔法。

标签: jsf jakarta-ee jsf-2 cdi


【解决方案1】:

使用 CDI。

根据 JSF 2.3,@ManagedBean弃用。另见spec issue 1417。这意味着不再有理由选择@ManagedBean 而不是@Named。这首先在 Mojarra 2.3.0 beta 版本 m06 中实现。


历史

核心区别在于,@ManagedBean 由 JSF 框架管理,并且仅通过 @ManagedProperty 可用于另一个 JSF 托管 bean。 @Named 由应用程序服务器(容器)通过 CDI 框架管理,并且通过 @Inject 可用于任何类型的容器管理工件,例如 @WebListener@WebFilter@WebServlet@Path@Stateless等,甚至是 JSF @ManagedBean。另一方面,@ManagedProperty 确实@Named 或任何其他容器管理的工件中工作。它实际上只在 @ManagedBean 内部有效。

另一个区别是,CDI 实际上在每个请求/线程的基础上注入委托给目标范围内当前实例的代理(就像注入 EJB 的方式一样)。这种机制允许将一个范围更窄的 bean 注入一个范围更广的 bean 中,而这在 JSF @ManagedProperty 中是不可能的。 JSF 通过调用 setter 直接在此处“注入”物理实例(这也正是需要 setter 的原因,而 @Inject不需要)。

虽然不是直接的缺点——还有其他方式——@ManagedBean 的范围只是有限的。从另一个角度来看,如果你不想为@Inject 暴露“太多”,你也可以只保留你的托管bean @ManagedBean。这就像 protectedpublic。但这并不重要。

至少,在 JSF 2.0/2.1 中,通过 CDI 管理 JSF 支持 bean 的主要缺点是没有与 @ViewScoped 等效的 CDI。 @ConversationScoped 很接近,但仍然需要手动启动和停止,并且它会在结果 URL 中附加一个丑陋的 cid 请求参数。 MyFaces CODI 通过完全透明地将 JSF 的 javax.faces.bean.ViewScoped 桥接到 CDI 使您可以更轻松地执行 @Named @ViewScoped,但是这会将丑陋的 windowId 请求参数附加到结果 URL,也在普通的页面到页面导航上。 OmniFaces 使用真正的 CDI @ViewScoped 解决了这一切问题,它真正将 bean 的范围与 JSF 视图状态联系起来,而不是与任意请求参数联系起来。

JSF 2.2(在此问题/答案 3 年后发布)提供了一个新的完全兼容 CDI 的 @ViewScoped 注释,以 javax.faces.view.ViewScoped 的风格开箱即用。 JSF 2.2 甚至附带了一个仅限 CDI 的 @FlowScoped,它没有等效的 @ManagedBean,从而将 JSF 用户推向 CDI。预计 @ManagedBean 和朋友将根据 Java EE 8 被弃用。如果您目前仍在使用 @ManagedBean,因此强烈建议切换到 CDI 为将来的升级路径做好准备。 CDI 在与 Java EE Web Profile 兼容的容器中很容易获得,例如 WildFly、TomEE 和 GlassFish。对于 Tomcat,您必须单独安装它,就像您已经为 JSF 所做的那样。另见How to install CDI in Tomcat?

【讨论】:

  • 我创建了beans.xml,将@ManagedBean 支持bean 转换为@Named,并将@ManagedProperty 转换为@Inject。世界一切安好。但是,如果我将 @EJB 注释更改为 @Inject,部署将失败 (org.jboss.weld.exceptions.DeploymentException) 并显示消息 WELD-001408 Injection point has unsatisfied dependencies。我真的应该使用@Inject 将无接口EJB 注入@Named bean,还是应该坚持使用@EJB? EJB 被打包在一个 EJB JAR 中,与包含我的 CDI bean 的 WAR 在同一个 EAR 中。
  • 它应该可以正常工作。您是否仍然面临当前 Weld 版本的这个问题?
  • 唉,我不能说。这个问题来自 2 位雇主且 > 2 年前。根据我对 Bozho 回答的旧评论,我一定已经切换到 CDI/@Named
  • "MyFaces CODI 通过将 JSF 的 javax.faces.bean.ViewScoped 完全透明地桥接到 CDI 使其变得更容易,因此您只需执行 @Named @ViewScoped,但是这会将丑陋的 windowId 请求参数附加到结果URL,也可以在普通的页面到页面导航上。” 请注意,对于 DeltaSpike,这不再适用。如果不需要 Window Scope,可以禁用 dsId 和 windowId URL 参数。
  • @Jan:同时,OmniFaces 还有一个类似 JSF 2.2 的 @ViewScoped 用于 JSF 2.0/2.1:showcase.omnifaces.org/cdi/ViewScoped
【解决方案2】:

CDI 优于普通 JSF,因为 CDI 允许 JavaEE 范围的依赖注入。您还可以注入 POJO 并让它们进行管理。使用 JSF,您只能注入 CDI 的一部分。

【讨论】:

  • 所以基本上,我可以注入几乎任何类的实例(只要它有“正确的东西” - 它是什么,只是一个无参数的构造函数?) CDI,如果我想用纯 JSF 注入它,我必须使用@ManagedBean
  • @MattBall Matt 在你多年之后,你能评论一下这次迁移吗?
  • @KorayTugay 自 2011 年 6 月以来我没有接触过这段代码,但我已经切换到 CDI 并且一切正常。如果您有任何具体问题,我很乐意尽我所能回答。
【解决方案3】:

在 Java EE 6 和 CDI 中,托管 Bean 有不同的选择

  • @javax.faces.bean.ManagedBean 是指 JSR 314,并在 JSF 2.0 中引入。主要目标是避免在 faces-config.xml 文件中进行配置以使用 JSF 页面中的 bean。
  • @javax.annotation.ManagedBean(“myBean”) 由 JSR 316 定义。它概括了 JSF 托管 bean,以便在 Java EE 的其他地方使用
  • @javax.inject.Named(“myBean”) 和上面的几乎一样,只是需要 web/WEB-INF 文件夹下的 beans.xml 文件来激活 CDI。

【讨论】:

【解决方案4】:

我在 GlassFish 3.0.1 中使用 CDI,但为了让它工作,我必须导入 Seam 3 框架 (Weld)。效果很好。

在 GlassFish 3.1 中,CDI 停止工作,Seam Weld 停止使用它。我打开了bug on this,但还没有看到它修复。我不得不将我的所有代码都转换为使用 javax.faces.* 注释,但我计划在它们正常工作后回到 CDI。

我同意您应该使用 CDI,但我还没有看到解决的一个问题是如何处理 @ViewScoped 注释。我有很多依赖于它的代码。如果您不使用@ManagedBean,则尚不清楚@ViewScoped 是否有效。如果有人能澄清这一点,我将不胜感激。

【讨论】:

    【解决方案5】:

    迁移到 CDI 的一个很好的理由:您可以将一个公共会话范围资源(例如用户配置文件)@Inject'ed 到 JSF 托管 bean 和 REST 服务(即 Jersey/JAX-RS)中。

    另一方面,@ViewScoped 是坚持使用 JSF @ManagedBean 的一个令人信服的理由——尤其是对于任何具有重要 AJAX 的东西。在 CDI 中没有标准的替代品。

    似乎它可能对CDI bean的@ViewScoped-like注解有一些支持,但我没有亲自玩过。

    http://seamframework.org/Seam3/FacesModule

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-26
      • 1970-01-01
      • 2012-04-12
      • 2014-06-12
      • 2014-03-10
      • 2014-01-08
      • 1970-01-01
      相关资源
      最近更新 更多