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

2022-08-31 09:37:36

我觉得Java EE 6规范有点混乱。有几组批注。

我们有像和创建EJB这样的注释。javax.ejb@Stateful@Stateless

还有一个用于创建受管理的 Bean。@javax.annotation.ManagedBean

在 like 和 中有注释。javax.enterprise.context@SessionScoped@RequestScoped

更重要的是,包装中还有和/注释。@ManagedBean@SessionScoped@RequestScopedjavax.faces.bean

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

有人可以描述一下它们是如何相互关联的吗?

我在哪里可以使用 ,或注射其他豆类?@EJB@Inject@ManagedPropery


答案 1

首先让我做一些澄清:

受管 Bean 定义 :通常受管 Bean 是其生命周期(构造、销毁等)由容器管理的对象。

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

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

所以我们可以说我们有:

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

因此,当您看到托管 Bean 单词时,您应该询问它的上下文或类型。(JSF,CDI,EJB等)

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

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

在那之后,加文·金和其他一些好人;)制作了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 管理豆

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

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

可以使用包中定义的不同作用域之一(包括请求、会话、应用程序、视图和自定义作用域)将作用域应用于 Bean。javax.faces.bean

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

如果没有某种手动编码,JSF豆就不能与其他类型的豆子混合。

CDI 豆

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

要部署 CDI Bean,必须将一个名为 bean.xml 的文件放在类路径上的 META-INF 文件夹中。一旦你这样做了,那么包中的每个bean都成为CDI Bean。CDI 中有很多功能,太多了,无法在此介绍,但作为类似 JSF 的功能的快速参考,您可以使用包中定义的作用域之一(即请求、会话、会话和应用程序作用域)来定义 CDI Bean 的作用域。如果要使用 JSF 页面中的 CDI Bean,可以使用注释为其命名。要将一个 Bean 注入到另一个 Bean 中,请使用注释对字段进行注释。javax.enterprise.contextjavax.inject.Namedjavax.inject.Inject

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

    @Inject
    private SomeService someService;
}

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

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

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

EJB

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

  • 事务
  • 远程或本地
  • 能够钝化有状态的豆子,释放资源
  • 能够利用定时器
  • 可以是异步的

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

定义 EJB 很简单,只需向类中添加 a 或 注释即可。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,但这可以通过为其编写一个简单的生产者方法来实现。

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

何时使用哪种豆子

你怎么知道什么时候使用哪种豆子?简单。

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

通常,您应该使用 CDI Bean,除非您需要 EJB 中提供的高级功能,如事务函数。你可以编写自己的拦截器来使 CDI bean 成为事务性的,但是就目前而言,在 CDI 获得即将到来的事务性 CDI Bean 之前,使用 EJB 会更简单。如果您被困在 servlet 容器中并且正在使用 CDI,那么手写事务或您自己的事务拦截器是唯一没有 EJB 的选项。

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

  • 使用接缝面MyFaces CODI 模块。只需将其中一个添加到您的类路径中,即可在CDI中工作。MyFaces CODI拥有更坚实的支持@ViewScoped@ViewScoped
  • 使用MyFaces CODI的,它是Apache在CDI之上编写的扩展,只需下载它并使用注释而不是。@ViewAccessScoped@ViewAccessScoped@ViewScoped
  • 使用 CDI 并使其长时间运行。有关详细信息,请参阅此处@ConversationScoped
  • 使用全面@ViewScoped注释

有些部分从这里偷来的。


答案 2

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

由于一些历史原因,JSF 和 CDI 对作用域使用相同的注释,但来自不同的包。

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

我通常建议您浏览优秀焊缝文档的前几页(甚至更多)。这应该会让你走上Java EE 6的轨道。

并随时在这里发布进一步的问题。


推荐