Java EE 6 @ javax.annotation.ManagedBean与@javax.inject.named比较@ javax.faces.ManagedBean

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

我们有像@Stateful@Stateless这样的javax.ejb注释来创buildEJB。

还有一个@javax.annotation.ManagedBean来创build一个托pipe的bean。

javax.enterprise.context有注释,如@SessionScoped@RequestScoped

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

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

有人可以描述他们是如何相互关联?

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

首先让我做一些澄清:

托pipebean定义托pipebean通常是一个对象,它的生命周期(构造,销毁等)由容器pipe理。

在Java EE中,我们有许多容器pipe理对象的生命周期,如JSF容器,EJB容器,CDI容器,Servlet容器等。

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

所以我们可以说我们有:

  • JSFpipe理的bean
  • CDI托pipe的豆子
  • EJBpipe理的bean
  • 甚至Servlet也是被pipe理的bean,因为它们被一个容器(一个servlet容器)实例化和销毁。

所以当你看到Managed Bean的话,你应该询问它的上下文或types(JSF,CDI,EJB等)

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

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

之后,加文·金和其他一些好人;)使CDI,这是我见过的最成熟的DI容器。 CDI(灵感来自Seam2,Guice和Spring)是为了填补JSF和EJB以及许多其他有用的东西,如pojo注入,生产者方法,拦截器,装饰器,集成SPI,非常灵活等等,甚至可以做EJB和JSF托pipe的bean在做什么,那么我们可以只有一个成熟和强大的DI容器。 但是对于一些向后兼容和政治上的原因,Java EE的人想保留它们!

在这里你可以find每种types的区别和用例:

JSF受pipeBean,CDI Bean和EJB

JSF最初是使用自己的托pipebean和dependency injection机制开发的,JSF 2.0增强了包含基于注释的bean的dependency injection机制。 当CDI与Jav​​a EE 6一起发布时,它被认为是该平台的托pipebean框架,当然,EJB已经过时了十多年。

当然问题是知道使用哪一个,什么时候使用它们。

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

JSF托pipe豆

简而言之,如果您正在开发Java EE 6并使用CDI,请不要使用它们。 它们为dependency injection和为Web页面定义后台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是作为Java EE 6的一部分发布的beanpipe理和dependency injection框架,它包含一个完整的,全面的托pipebean工具。 CDI bean比简单的JSFpipe理的bean要先进和灵活得多。 他们可以利用拦截器,会话范围,事件,types安全注入,装饰器,定型和生成器方法。

要部署CDI bean,您必须将名为beans.xml的文件放在类path的META-INF文件夹中。 一旦你这样做了,那么包中的每个bean就成为一个CDI bean。 在CDI中有很多function,可以覆盖太多,但是作为JSF-likefunction的快速参考,您可以使用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; } 

像上面定义的自动注射可以通过使用限定符来控制,这些限定符可以帮助匹配要注入的特定类。 如果您有多种支付types,则可以添加限定符以确定是否为asynchronous。 虽然您可以使用@Named注释作为限定符,但您不应该像在EL中公开bean一样。

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

CDI还支持拦截器,事件,新的对话范围和许多其他function,使它成为比JSF托pipe的bean更好的select。

EJB

EJB早于CDI bean,并且在某种程度上类似于CDI bean,而在其他方面则非常不同。 首先,CDI bean和EJB之间的区别在于EJB是:

  • 交易
  • 远程或本地
  • 能够钝化有状态的豆释放资源
  • 能够使用定时器
  • 可以是asynchronous的

这两种types的EJB被称为无状态和有状态的。 无状态的EJB可以被认为是线程安全的单用户Bean,它们不会在两个Web请求之间保持任何状态。 有状态EJB持有状态,只要需要,它们可以被创build和坐下,直到它们被丢弃。

定义一个EJB很简单,只需要在类中添加一个javax.ejb.Stateless或者javax.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

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

切勿使用JSF托pipe的bean,除非您正在使用servlet容器,并且不想尝试让CDI在Tomcat中工作(尽pipe这里有一些Maven原型,所以没有借口)。

一般来说,除非需要EJB中提供的高级function(如事务function),否则应该使用CDI Bean。 你可以编写自己的拦截器来使CDI bean成为事务性的,但现在,使用EJB直到CDI获得即将到来的事务性CDI bean才更简单。 如果你被困在一个servlet容器中并使用CDI,那么无论是手写事务还是你自己的事务拦截器都是没有EJB的唯一select。

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

  • 使用seam-faces或MyFaces CODI模块。 只需将其中一个添加到您的类path中, @ViewScoped将在CDI中工作。 MyFaces CODI对@ViewScoped提供了更坚实的支持
  • 使用MyFaces CODI的@ViewAccessScoped ,它是由Apache编写在CDI之上的一个扩展,只需下载它并使用@ViewAccessScoped注释而不是@ViewScoped
  • 使用CDI @ConversationScoped并使其长时间运行。 在这里看到更多的信息 。
  • 使用Omnifaces @ViewScoped注释

有些地方从这里偷窃。

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

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

正如您可能猜测那些来自javax.faces.bean是来自JSF规范,并且与CDI无关。 除非你有足够的理由这样做,否则不要使用它们。 永远不要将它们与来自javax.ejb CDI注释混合在一起。 这将产生一个错综复杂的错误和微妙的exception名单。

我通常build议您浏览优秀焊接文档的前几个(或更多)页面。 这应该使您对Java EE 6有所了解。

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

由于没有关于@javax.annotation.ManagedBean具体回复,下面是一个类似问题的答案的链接: Backing beans(@ManagedBean)或者CDI Beans(@Named)? 。 该规范可以在http://download.oracle.com/otndocs/jcp/managed_beans-1.0-fr-eval-oth-JSpec/find。; 所以在我看来, @javax.annotation.ManagedBean是为了@javax.faces.bean.ManagedBean的泛化。

从我所搜集到的情况来看,JSF Managed Beans正逐渐被淘汰,可能会被弃用于JSF 2.3,所以我猜@javax.annotation.ManagedBean现在已经变得过时了。