是支持bean(@ManagedBean)还是CDI Bean(@Named)?


109

我刚刚开始阅读Core JavaServer Faces,第三版。他们这样说(强调我的意思):

对于可以在JSF页面中使用的bean,有两种单独的机制(CDI bean和JSF管理的bean)是历史上的意外。我们建议您使用CDI bean,除非您的应用程序必须在诸如Tomcat之类的普通servlet运行程序上运行。

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



4
@Bozho:这个问题非常相似,但是在阅读了Pascal的答案几次之后,我仍然不明白为什么 CDI会更好。我不了解CDI,并且很高兴学习它,因为它“更好”。为什么会更好?
马特·鲍尔

“除非您的应用程序必须在像Tomcat这样的普通servlet运行器上运行,否则我只能使用tomcat,我强烈建议使用CDI。Tomcat可以很好地支持它
KarlKildén2012年

1
@KarlKildén“普通servlet运行程序”是指不具备CDI功能的servlet容器。在撰写本文时,Tomcat颇具魔力,不支持CDI。
托尔比约恩Ravn的安德森

Answers:


64

CDI比纯JSF更可取,因为CDI允许JavaEE范围内的依赖注入。您还可以注入POJO并对其进行管理。使用JSF,您只能注入CDI的一部分。


因此,基本上,我可以使用CDI 注入几乎任何类的实例(只要它具有“正确的东西”- 它是什么,只是一个无参数的构造函数?),而@ManagedBean如果我想用普通的方式注入它,则必须使用JSF?
马特·鲍尔

3
@MattBall马特(Matt)在您工作多年后,您可以对此次迁移发表评论吗?
Koray Tugay

5
@KorayTugay自2011年6月以来我一直没有碰过这段代码,但是我改用了CDI,一切正常。如果您有任何疑问,我很乐意回答所有具体问题。
马特·鲍尔

170

使用CDI。

根据JSF 2.3,@ManagedBean弃用。另请参阅规格问题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方法(这也正是为什么需要一个二传手,而直接物理实例与要求@Inject)。

虽然不是直接不利,但还有其他方法,但范围@ManagedBean却很有限。从另一个角度看,如果您不想公开太多@Inject,也可以只保留托管bean @ManagedBean。就像protectedvs 一样public。但这并不真正重要。

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

JSF 2.2(在此问题/答案发布三年后发布)以的形式提供了一个新的,完全兼容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那样单独安装。另请参阅如何在Tomcat中安装CDI?


4
我创建beans.xml,转换后的@ManagedBean后盾豆@Named,并转换@ManagedProperty@Inject。世界一切安好。但是,如果我将@EJB注释更改为@Inject,则部署将失败(org.jboss.weld.exceptions.DeploymentException)并带有message WELD-001408 Injection point has unsatisfied dependencies。我是否应该实际上是@Inject在将无接口EJB注入到@Namedbean中,还是应该坚持使用@EJB?EJB打包在与包含我的CDI bean的WAR相同的EAR中的EJB JAR中。
Matt Ball 2010年

它应该工作。当前的Weld版本是否仍面临此问题?
BalusC

las,我不能说。这个问题来自2个雇主,并且是2年以前的。基于我对Bozho答案的旧评论,我必须切换到CDI / @Named
马特·鲍尔

“通过将JSF的javax.faces.bean.ViewScoped完全透明地桥接到CDI,MyFaces CODI使其变得更加容易,因此您可以执行@Named @ViewScoped,但是在普通的逐页导航中,也将丑陋的windowId请求参数附加到结果URL。” 请注意,对于DeltaSpike,这不再成立。如果不需要“窗口范围”,则可以禁用dsId和windowId URL参数。
2013年

1
@Jan:而在同时,OmniFaces还具有JSF 2.2状@ViewScoped为JSF 2.0 / 2.1:showcase.omnifaces.org/cdi/ViewScoped
BalusC

16

使用Java EE 6和CDI,您可以为Managed 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文件夹中的bean.xml文件来激活CDI。

1
前两者有什么区别?
Matt Ball 2010年

第一个注释的目标是/曾经要替换faces-config.xml中的Bean配置以供JSF使用。第二个将概念复制到“ java ee 6容器”中。它具有更多功能(例如@PostConstruct和@PreDestroy批注),但也可以通过JSF Page(具有表达式语言)来访问。
h2mch 2010年

1
为什么需要beans.xml文件?今天仍然如此吗?
Thufir

2
不,有了JavaEE7,您就不再需要beans.xml。参见docs.oracle.com/javaee/7/tutorial/doc/cdi-adv001.htm
h2mch 2014年

1
使用JavaEE7,您不需要bean.xml: docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm(正确链接) blogs.oracle.com/theaquarium/entry/…(Java中的默认CDI启用) EE 7)
M. Atif Riaz

2

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

在GlassFish 3.1中,CDI停止工作,而Seam Weld停止使用它。我为此打开了一个错误但尚未看到修复的问题。我必须将所有代码都转换为使用javax.faces。*批注,但我计划一旦它们起作用,便计划重新使用CDI。

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


-1

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

另一方面,这@ViewScoped是坚持使用JSF的一个令人信服的理由@ManagedBean-特别是对于具有大量AJAX的任何东西。CDI中没有标准替代品。

似乎它可能支持@ViewScopedCDI bean 的-like注释,但我个人还没有玩过它。

http://seamframework.org/Seam3/FacesModule

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.