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

时间:2012-08-16 12:11:30

标签: java java-ee java-ee-6 cdi

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

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

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

javax.enterprise.context中有@SessionScoped@RequestScoped的注释。

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

为了使事件更复杂,有一个javax.inject包含@Named注释。

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

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

3 个答案:

答案 0 :(得分:188)

首先让我做一些澄清:

托管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与Jav​​a EE 6一起发布时,它被认为是该平台的托管bean框架,当然,过时的EJB已经过时了十多年。

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

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

JSF Managed Beans

简而言之,如果您正在为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 Beans

CDI是作为Java EE 6的一部分发布的bean管理和依赖注入框架,它包含一个完整,全面的托管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,但可以通过为它编写一个简单的生成器方法来实现。

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

何时使用哪个bean

你怎么知道何时使用哪种豆?简单。

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

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

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

  • 使用seam-facesMyFaces CODI模块。只需将其中一个添加到您的类路径中,@ViewScoped将在CDI中工作。 MyFaces CODI对@ViewScoped
  • 有更强的支持
  • 使用MyFaces CODI&#39; @ViewAccessScoped,它是由Apache编写的CDI上的扩展,仅download它并使用@ViewAccessScoped注释而不是@ViewScoped
  • 使用CDI @ConversationScoped并使其长时间运行。见here for more info
  • 使用Omnifaces @ViewScoped注释

部分内容来自here

答案 1 :(得分:6)

是的,这可能令人困惑。

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

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

我通常建议您浏览优秀Weld documentation的前几页(或更多页)。这应该让您了解Java EE 6。

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

答案 2 :(得分:1)

由于没有专门针对@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现在已经过时了。