Java EE 6 @javax.annotation.ManagedBean 与 @javax.inject.Named 与 @javax.faces.ManagedBean

Posted

技术标签:

【中文标题】Java EE 6 @javax.annotation.ManagedBean 与 @javax.inject.Named 与 @javax.faces.ManagedBean【英文标题】:Java EE 6 @javax.annotation.ManagedBean vs. @javax.inject.Named vs. @javax.faces.ManagedBean 【发布时间】:2012-08-12 18:48:48 【问题描述】:

我觉得 Java EE 6 规范有些混乱。有几组注释。

我们有 javax.ejb 注释,例如 @Stateful@Stateless 用于创建 EJB。

还有一个@javax.annotation.ManagedBean来创建托管bean。

javax.enterprise.context 中有注解,如@SessionScoped@RequestScoped

此外,javax.faces.bean 包中还有 @ManagedBean@SessionScoped/@RequestScoped 注释。

为了让事情变得更复杂,还有一个带有 @Named 注释的包 javax.inject

有人可以描述一下它们之间的关系吗?

在哪里可以使用@EJB@Inject@ManagedPropery 注入其他bean?

【问题讨论】:

另见:***.com/questions/4684112/… 【参考方案1】:

首先让我做一些澄清:

托管 bean 定义:通常托管 bean 是一个对象,其生命周期(构造、销毁等)由容器管理。

在 Java ee 中,我们有许多容器来管理其对象的生命周期,例如 JSF 容器、EJB 容器、CDI 容器、Servlet 容器等。

所有这些容器都是独立工作的,它们在应用服务器初始化中启动,并在部署时扫描所有工件的类,包括 jar、ejb-jar、war 和 ear 文件,并收集和存储一些关于它们的元数据,然后当你在运行时需要一个类的对象,它们会给你这些类的实例,完成工作后,它们会销毁它们。

所以我们可以说我们有:

JSF 托管 bean CDI 托管 bean EJB 托管 bean 甚至 Servlet 也是托管 bean,因为它们是由一个容器实例化和销毁的,该容器是一个 servlet 容器。

所以当你看到 Managed Bean 这个词时,你应该询问它的上下文或类型。(JSF、CDI、EJB 等)

然后你可能会问为什么我们有很多这样的容器:AFAIK,Java EE 的人想要一个依赖注入框架,但是他们无法在一个规范中收集所有需求,因为他们无法预测未来的需求,他们制作了 EJB 1.0,然后是 2.0,然后是 3.0,现在是 3.1,但 EJB 的目标只是满足一些需求(事务、分布式组件模型等)。

同时(并行)他们意识到他们也需要支持 JSF,然后他们制作了 JSF 托管 bean 和另一个 JSF bean 容器,他们认为这是一个成熟的 DI 容器,但它仍然不完整和成熟容器。

在 Gavin King 和其他一些好人之后 ;) 制作了 CDI,这是我见过的最成熟的 DI 容器。 CDI(受 Seam2、Guice 和 Spring 启发)是为了填补 JSF 和 EJB 之间的空白以及许多其他有用的东西,如 pojo 注入、生产者方法、拦截器、装饰器、集成 SPI、非常灵活等,它甚至可以做EJB 和 JSF 托管 bean 正在做什么,那么我们就可以拥有一个成熟且强大的 DI 容器。但是出于一些向后兼容性和政治原因,Java EE 的人想要保留它们!!!

您可以在此处找到每种类型的区别和用例:

JSF 托管 Bean、CDI Bean 和 EJB

JSF 最初是使用自己的托管 bean 和依赖注入机制开发的,该机制在 JSF 2.0 中得到了增强,包括基于注释的 bean。当 CDI 与 Java EE 6 一起发布时,它被认为是该平台的托管 bean 框架,当然,EJB 已经过时了,它们已经存在了十多年。

问题当然是知道使用哪一个以及何时使用它们。

让我们从最简单的 JSF 托管 bean 开始。

JSF 托管 Bean

简而言之,如果您正在为 Java EE 6 开发并使用 CDI,请不要使用它们。它们为依赖注入和为网页定义支持 bean 提供了一种简单的机制,但它们远不如 CDI bean 强大。

可以使用带有可选名称参数的@javax.faces.bean.ManagedBean 注释来定义它们。此名称可用于引用 JSF 页面中的 bean。

可以使用 javax.faces.bean 包中定义的不同范围之一将范围应用于 bean,其中包括请求、会话、应用程序、视图和自定义范围。

@ManagedBean(name="someBean")
@RequestScoped
public class SomeBean 
    ....
    ....

JSF bean 不能在没有某种手动编码的情况下与其他种类的 bean 混合使用。

CDI 豆

CDI 是 bean 管理和依赖注入框架,作为 Java EE 6 的一部分发布,它包括一个完整、全面的托管 bean 设施。 CDI bean 比简单的 JSF 托管 bean 更加先进和灵活。他们可以利用拦截器、会话范围、事件、类型安全注入、装饰器、构造型和生产者方法。

要部署 CDI bean,您必须将名为 beans.xml 的文件放在类路径上的 META-INF 文件夹中。一旦执行此操作,包中的每个 bean 都将成为 CDI bean。 CDI 中有很多特性,这里就不一一介绍了,但作为 JSF 类特性的快速参考,您可以使用 javax.enterprise.context 包中定义的范围之一来定义 CDI bean 的范围(即,请求、对话、会话和应用范围)。如果要使用 JSF 页面中的 CDI bean,可以使用 javax.inject.Named 注释为其命名。要将 bean 注入另一个 bean,请使用 javax.inject.Inject 注释对字段进行注释。

@Named("someBean")
@RequestScoped
public class SomeBean 

    @Inject
    private SomeService someService;

可以通过使用限定符来控制上面定义的自动注入,这有助于匹配您想要注入的特定类。如果您有多种付款类型,您可以添加一个限定符来判断它是否是异步的。虽然您可以使用 @Named 注释作为限定符,但您不应该使用它,因为它是为在 EL 中公开 bean 而提供的。

CDI 通过使用代理来处理范围不匹配的 bean 注入。因此,您可以将请求范围的 bean 注入到会话范围的 bean 中,并且该引用对每个请求仍然有效,因为对于每个请求,代理都会重新连接到请求范围 bean 的实时实例。

CDI 还支持拦截器、事件、新的对话范围和许多其他功能,这使其成为比 JSF 托管 bean 更好的选择。

EJB

EJB 早于 CDI bean,在某些方面与 CDI bean 相似,但在其他方面则非常不同。首先,CDI bean 和 EJB 之间的区别在于 EJB 是:

事务性 远程或本地 能够钝化有状态的 bean 以释放资源 能够使用定时器 可以是异步的

这两种类型的 EJB 被称为无状态和有状态。无状态 EJB 可以被认为是线程安全的一次性 bean,它不维护两个 Web 请求之间的任何状态。有状态的 EJB 确实保持状态,并且可以在需要时被创建和保留,直到它们被处理掉。

定义 EJB 很简单,您只需在类中添加 javax.ejb.Statelessjavax.ejb.Stateful 注释即可。

@Stateless
public class BookingService 

  public String makeReservation(Item Item, Customer customer) 
    ...
    ...
  

无状态 bean 必须有一个依赖范围,而有状态会话 bean 可以有任何范围。默认情况下它们是事务性的,但您可以使用事务属性注释。

虽然 EJB 和 CDI bean 在功能方面非常不同,但编写代码来集成它们非常相似,因为 CDI bean 可以注入到 EJB 中,而 EJB 可以注入到 CDI bean 中。将一种注入另一种时无需区分。同样,CDI 通过使用代理来处理不同的范围。一个例外是 CDI 不支持远程 EJB 的注入,但可以通过为其编写一个简单的生产者方法来实现。

javax.inject.Named 注释以及任何限定符可用于 EJB 以将其与注入点匹配。

何时使用哪个 bean

你怎么知道什么时候使用哪个bean?很简单。

永远不要使用 JSF 托管 bean,除非您在 servlet 容器中工作并且不想尝试让 CDI 在 Tomcat 中工作(尽管有一些 Maven 原型,所以没有任何借口)。

一般来说,您应该使用 CDI bean,除非您需要 EJB 中可用的高级功能,例如事务功能。您可以编写自己的拦截器来使 CDI bean 事务化,但是现在,使用 EJB 更简单,直到 CDI 获得即将到来的事务性 CDI bean。如果您被困在 servlet 容器中并使用 CDI,那么手写事务或您自己的事务拦截器是没有 EJB 的唯一选择。

如果你需要在 CDI 中使用@ViewScoped,你应该

使用seam-faces 或MyFaces CODI 模块。只需将其中一个添加到您的类路径中,@ViewScoped 将在 CDI 中工作。 MyFaces CODI 对@ViewScoped 的支持更加稳固 使用 MyFaces CODI 的 @ViewAccessScoped,它是 Apache 在 CDI 之上编写的扩展,只需 download 它并使用 @ViewAccessScoped 注释而不是 @ViewScoped。 使用 CDI @ConversationScoped 并使其长时间运行。见here for more info。 使用Omnifaces@ViewScoped 注解

从here窃取的部分零件。

【讨论】:

这太棒了!谢谢!为了完整起见,只需说明如何将 CDI 或 EJB bean 注入 JSF bean。 @ManagedProperty("#someBean)" 是正确的方式吗? 不!它行不通。只需使用@Named@javax.enterprise.context.RequestScoped 将您的jsf 托管bean 转换为CDI 托管bean,并使用@Inject 注释使用CDI 注入。如果不需要,请不要使用 jsf 托管 bean;)。 >JEE 家伙想要保留它们! - 它比这更微妙。 CDI 在 Java EE 6 周期的后期完成,而 JSF 2 和 JAX-RS 都已经完成。他们增强了响应。已经引入了他们自己的托管 bean 设施。如果 CDI 早一点可用,情况可能会有所不同。在 Java EE 7 中,JSF 将采用 CDI,而 javax.faces.bean 最终将被弃用(但在 Java EE 中弃用是一个缓慢的过程,这有好有坏)。 当您说:要部署 CDI bean,您必须将一个名为 beans.xml 的文件放在类路径上的 META-INF 文件夹中。一旦执行此操作,包中的每个 bean 都将成为 CDI bean。你的意思是每个 bean 除了它是什么之外,也变成了一个 CDI bean?如果我有带有 ManagedBean 和 ViewScoped 的 JSF ManagedBeans 怎么办。它们仍然是 JSF 托管 Bean,对吗? 有人能在这篇精彩的文章中更新 Java EE 7 吗?【参考方案2】:

是的,这可能会令人困惑。

出于某些ehm历史原因,JSF 和 CDI 对范围使用相同的注释,但来自不同的包。

正如您可能猜到的,来自javax.faces.bean 的那些来自 JSF 规范,与 CDI 无关。除非您有充分的理由这样做,否则不要使用它们。并且永远不要将它们与来自javax.ejb 的 CDI 注释混合在一起。这将产生无穷无尽的错误和细微异常列表。

我通常建议您浏览出色的Weld documentation 的前几页(甚至更多)。这应该会让您走上 Java EE 6 的轨道。

并随时在此处发布更多问题。

【讨论】:

其实我有两个问题: 1. 我经常发现视图范围非常有用。那我需要使用JSF注解吗? 2. 这意味着@javax.annotation.ManagedBean 没有用,因为CDI 将所有类都视为托管bean,对吗? 不完全。您将需要使用例如将 JSF 范围桥接到 CDI。接缝面。是的,如果相关的 jar 文件中有 beans.xml,则不需要 @ManagedBeans。哦,如果您还有其他问题,最好在我们在评论部分放松之前开始一个新线程。【参考方案3】:

由于没有专门针对@javax.annotation.ManagedBean 的回复,这里有一个类似问题答案的链接:Backing beans (@ManagedBean) or CDI Beans (@Named)?。可以在http://download.oracle.com/otndocs/jcp/managed_beans-1.0-fr-eval-oth-JSpec/ 找到规范。所以在我看来@javax.annotation.ManagedBean@javax.faces.bean.ManagedBean 的泛化。

根据我收集到的信息,JSF Managed Beans 正在逐步淘汰,取而代之的是 CDI Beans(可能从 JSF 2.3 中被弃用?),所以我猜@javax.annotation.ManagedBean 现在越来越过时了。

【讨论】:

@Named 将来会取代@ManagedBean 吗? 我已经阅读了不同 Java EE 专家的一些声明,他们预测 CDI @Named bean 将取代 JSF @ManagedBeans,例如在***.com/questions/4347374/… 中,BalusC 说“预计@ManagedBean 和朋友将根据 Java EE 8 被弃用。”。

以上是关于Java EE 6 @javax.annotation.ManagedBean 与 @javax.inject.Named 与 @javax.faces.ManagedBean的主要内容,如果未能解决你的问题,请参考以下文章

Java EE 6 和 CDI

构建 Java EE 6 项目时出现 FilerException

Java EE 6:切换到 CDI - 最佳资源

针对 Java EE 6 API 进行测试

Spring Security 和 Java EE 6 集成

Maven - Java EE 6 Web 配置文件 Javadocs