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

Pio*_*zda 107 java java-ee cdi java-ee-6

我觉得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注入其他豆类?

Hei*_*deh 192

首先让我做一些澄清:

托管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带有可选name参数的注释来定义它们.此名称可用于从JSF页面引用bean.

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

@ManagedBean(name="someBean")
@RequestScoped
public class SomeBean {
    ....
    ....
}
Run Code Online (Sandbox Code Playgroud)

如果没有某种手动编码,JSF bean不能与其他类型的bean混合使用.

CDI豆

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;
}
Run Code Online (Sandbox Code Playgroud)

可以通过使用有助于匹配您想要注入的特定类的限定符来控制上面定义的自动注入.如果您有多种付款类型,则可以添加限定符,以确定它是否是异步的.虽然您可以将@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.Stateless或一个javax.ejb.Stateful注释即可.

@Stateless
public class BookingService {

  public String makeReservation(Item Item, Customer customer) {
    ...
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

javax.inject.Named注释以及任何限定符可在一个EJB被用于匹配到注入点.

何时使用哪个bean

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

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

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

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

  • 使用seam-facesMyFaces CODI模块.只需将其中一个添加到类路径中,即可@ViewScoped在CDI中使用.MyFaces CODI对@ViewScoped有更强大的支持
  • 使用MyFaces CODI @ViewAccessScoped,它是由Apache编写在CDI之上的扩展,只需下载它并使用@ViewAccessScoped注释而不是@ViewScoped.
  • 使用CDI @ConversationScoped并使其长时间运行.见此处获得更多信息.
  • 使用Omnifaces @ViewScoped注释

有些地方从这里偷走.

  • 这很棒!谢谢!要完成,只需告诉如何将CDI或EJB bean注入JSF bean.`@ManagedProperty("#{someBean})"`是正确的方法吗? (3认同)
  • > JEE的人想留住他们! - 它比那更微妙.CDI在Java EE 6周期中完成得很晚,JSF 2和JAX-RS都已经完成了.他们增强了分辨率.已经介绍了他们自己的托管bean设施.如果CDI早一点可用,事情可能会有所不同.在Java EE 7中,JSF将采用CDI,javax.faces.bean最终将被弃用(弃用在Java EE中是一个缓慢的过程,这既好又坏). (3认同)
  • 当您说:要部署CDI bean,您必须将名为beans.xml的文件放在类路径的META-INF文件夹中.一旦你这样做,那么包中的每个bean都变成了一个CDI bean.你的意思是除了它之外,每个bean还会成为CDI bean吗?如果我有ManagedBean和ViewScoped的JSF ManagedBeans怎么办?他们还是JSF Managed Beans吧? (3认同)
  • 有人能够在这篇伟大的文章上对Java EE 7进行更新吗? (3认同)
  • 不!它不会起作用.只需将您的jsf托管bean转换为CDI托管bean,方法是使用`@ Named`和`@javax.enterprise.context.RequestScoped`进行注释,并使用@Inject注释使用CDI注入.如果你不需要,请不要使用jsf托管bean;). (2认同)

jan*_*oth 6

是的,这可能令人困惑.

对于一些EHM历史原因JSF和CDI使用的是相同的注解范围,但是从不同的包.

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

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

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


Hei*_*löd 5

由于没有专门针对 的回复@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现在它变得更加过时了。