问题
假设我们部署的存档是一个"隐式bean存档"(见下文),使用@javax.inject.Inject
将@javax.annotation.ManagedBean
注入到WildFly 8.1.0中的另一个托管bean工作中,但它不会在GlassFish 4.0.1-b08和GlassFish 4.1-b13中工作。GlassFish崩溃,显示如下信息:
WELD-001408:类型…不满足依赖
是我误解了以下概述的规范,还是GlassFish有bug?
CDI 1.1 Part 1
CDI 1.1 (JSR-346)第12.1节"Bean Archives"说:
显式bean归档是包含beans.xml文件的归档[…]。隐式bean归档是包含一个bean的任何其他归档或者更多带有bean定义注释的bean类[…]。
如果这样,我的存档没有beans.xml
描述符文件,我仍然能够使用具有"bean定义注释"的bean。问题是,什么是bean定义注释?
CDI规范第2.5节"Bean定义注释"说:
任何作用域类型都是bean定义注释。
这是非常清楚的,根据CDI规范的这一部分,这就是它的全部内容。如果我部署的归档文件中没有beans.xml
描述符文件,那么只要bean具有显式声明的作用域(例如@javax.enterprise.context.RequestScoped
),我就可以@Inject bean。它适用于WildFly和GlassFish。然而. .
托管bean
Java EE技术栈中的所有规范都必须遵守的子集规范,托管bean (JSR-316),具有一个"基本模型",其中@javax.annotation.ManagedBean
确实定义了一个托管bean。托管bean规范并没有说@ManagedBean
使bean成为注入点(即字段或参数)的合理的注入目标。规范确实说bean"可以在Java EE应用程序的任何地方使用"(章节MB.1.2"为什么要管理bean ?"),在我看来,它们也应该是可注入的。
Java EE 7 Umbrella规范
Java EE 7规范(JSR-342)在EE.5.24节"对依赖注入的支持"中有这样的说明:
容器必须支持用仅在CDI指定的范围内注入注释。每在CDI规范中,托管依赖注入是受支持的豆子。
目前有三种方法使类成为受管bean:
- 作为EJB会话bean组件。
- 使用ManagedBean注释进行注释。
- 满足CDI规范中描述的条件。
至少满足其中一个条件的类才有资格以获得CDI中描述的完全依赖注入支持规范。
好了:@ManagedBean有"完全依赖注入支持"。不是一半,也不是一点点支持。然而,我不确定"依赖注入支持"到底是什么。但我认为下面的段落已经很好地描述了它:
基本上,这段话说的是第二个条件是CDI托管bean可以被注入到其他托管类中(因为异常bean"也可以")。表EE.5-1中列出的满足第三个条件的组件类上述条件,但第一个和第二个条件都不能如果用CDI进行了注释,也可以用作CDI管理beanbean定义注释或包含在bean归档文件中,CDI为其定义注释启用。但是,如果将它们用作CDI管理bean(例如,注入到其他托管类中),即被管理的实例由CDI管理的实例可能不是由Java EE管理的实例容器。
伞形规范和托管bean规范都在一定程度上表明,CDI规范拥有最终决定权。
CDI 1.1 Part 2
@ManagedBean
注释在CDI规范中只被提及两次,这两次都出现在第11章中,这一章讲述了CDI扩展可以观察到的生命周期CDI事件。第11.5.7节定义了一个ProcessInjectionPoint
事件。托管bean可以使用依赖注入——这并不奇怪。但是,第11.5.8节定义了ProcessInjectionTarget
事件。以下是规范对ProcessInjectionTarget事件的说明:
容器必须为每个Java EE组件类触发一个事件支持可以被容器实例化的注入运行时,包括使用@ManagedBean声明的每个托管bean, EJB会话或消息驱动bean、bean、拦截器或装饰器。
这句话毫无疑问地表明,@ManagedBean
可以用作注入点的目标,而无需添加作用域类型的概念(@Dependent总是默认的)。
如前所述,从隐式bean存档中注入@ManagedBean在WildFly中工作,据我所知,这是刚才引用的所有Java EE规范所要求的。所以我认为是GlassFish有问题。但是CDI规范在2.5节"Bean定义注释"中从来没有提到@ManagedBean,而且和往常一样,当我阅读重叠的Java EE规范时,我总是很紧张,所以我认为我应该在向GlassFish团队提交一个"严重"错误之前问一下。
编辑2014-08-22
提交了一个GlassFish bug: https://java.net/jira/browse/GLASSFISH-21169.
这不是一个完整的答案,因为当我们试图把所有规范放在一起并弄清楚它们的意义时,不可避免地会出现混乱。我只是想说,CDI 1.2已经澄清了bean定义注释的确切含义(参见"2.5.1"节)。Bean定义注释")。CDI 1.2给出一个列表:
bean定义注解集包含:
- @ApplicationScoped, @SessionScoped, @ConversationScoped和@RequestScoped注释,
- 所有其他正常作用域类型,
- @Interceptor和@Decorator注释,
- 所有的原型注释(即用@Stereotype注释的注释),
- 和@Dependent作用域注释
应该补充的是,定义"正常作用域类型"(第二个要点)的是一个标注了@NormalScope的自定义作用域。