CDI 1.1中注解的bean发现模式的含义

Posted

技术标签:

【中文标题】CDI 1.1中注解的bean发现模式的含义【英文标题】:Meaning of bean discovery mode annotated in CDI 1.1 【发布时间】:2013-08-21 01:09:47 【问题描述】:

我正在将应用程序迁移到 Java EE 7 并希望迁移到 CDI 1.1。但我不明白bean-discovery-mode="annotated" 的含义。这 CDI 1.1 specification 不是很有帮助。至少我还没有找到任何有用的段落。我错过了吗?

这个例子与bean-discovery-mode="all"完美运行并注入LoggingClass的一个实例:

public class LoggingClass 
    public Logger logger = Logger.getLogger("ALOGGER");



@Test
public class MMLoggerProducerIT extends Arquillian 

    @Inject private LoggingClass lc;


但是,如果我从 bean-discovery-mode="all" 更改为 bean-discovery-mode="annotated",则容器无法将实例注入字段 lc

如何注释LoggingClass 才能正确使用bean-discovery-mode="annotated"

【问题讨论】:

我只是猜测,但我认为 '@Named' 或 ''@ManagedBean' 会是候选人? @Mike_Braun Named 只会在 EL 上下文中公开一个 bean,但不会给它一个范围。 ManagedBean 是一个 JSF 注解,CDI 引擎会忽略它。 【参考方案1】:

当使用bean-discovery-mode="annotated" 时,仅使用具有bean 定义注释 are discovered 的类。所有其他类都被忽略。 任何作用域类型都是定义注解的 bean。如果在 bean 类上声明了范围类型,则称该 bean 类具有 bean 定义注释 [规范]。 1.1 规范在这里并不完全清楚。仅发现具有@NormalScope 作用域或@Dependent 伪作用域的类、@javax.inject.Singleton 和所有其他@Scope(伪)作用域are ignored。

请注意,“bean 定义注释”的定义在 CDI 1.2 中发生了变化,现在定义得很好:

定义注解的bean集合包含:

@ApplicationScoped、@SessionScoped、@ConversationScoped 和 @RequestScoped 注释, 所有其他普通范围类型, @Interceptor 和@Decorator 注释, 所有原型注解(即用@Stereotype注解的注解), 和 @Dependent 范围注释。

【讨论】:

【参考方案2】:

实际上,bean-discovery-mode="ALL" 会开启对存档中所有类的扫描。这称为“显式存档”。

省略 beans.xml 或设置 bean-discovery-mode="ANNOTATED",会使存档成为隐式存档。在这种情况下,容器将扫描带有注解作用域类型的 bean。

这解释了为什么在设置bean-discovery-mode="ANNOTATED" 时不会注入LoggingClass。如 Java EE 7 教程中所述:

CDI 只能管理和注入在隐式存档中使用范围类型注释的 bean。

编辑:为了绝对清楚,您需要向LoggingClass 添加范围类型。所以是这样的:

@SessionScoped
public class LoggingClass 
    public Logger logger = Logger.getLogger("ALOGGER");

在 Java EE 7 和 CDI 1.1 中,我们删除了包含 beans.xml 部署描述符以为存档打开 CDI 的要求,使 CDI 1.1 与部署描述符是可选的大多数其他 Java EE API 保持一致。它还删除了是否包含beans.xml 的二进制开/关性质。您可以通过bean-discovery-mode中的设置来控制容器扫描哪些文件。

在此处查看有关打包 CDI 应用程序的 JavaEE 教程: http://docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm#CACDCFDE

【讨论】:

如果没有beans.xml,拦截器和装饰器是如何注册和排序的?有办法吗? @nosuchnick 拦截器可以通过使用@Interceptors@Priority 的注释来订购,如in section 54.2.5 here 所述。 它是否描述了如何让@Produces 工作?我必须在 Factory 类上添加注释吗?【参考方案3】:

我也同意@rmuller 的回答形式。但我想指出的是,应用服务器 Payara 和 Wildfly 上仍然存在不同的行为。 请参阅以下示例,其中包含普通的非作用域类但具有 @EJB 注入:

public class SomeClass  
    @EJB
    MyService myService;

   ...

如果您提供 beans.xml 文件:

 .... version="1.2" bean-discovery-mode="annotated"....

Payara 4.1 将不将类 SomeClass 视为 CDI bean,并且不会注入服务 EJB。 我很清楚它的行为如规范中所述。

但 Wildfly 10 将该类视为 CDI bean 并注入了预期之外的服务 EJB。要使其正常工作, beans.xml 文件应如下所示:

 .... version="1.2" bean-discovery-mode="all"....

令人惊讶的是,两个最常见的应用程序服务器在行为上是不同的。

【讨论】:

以上是关于CDI 1.1中注解的bean发现模式的含义的主要内容,如果未能解决你的问题,请参考以下文章

@repository的含义,并且有时候却不用写,为什么?

使用 Payara 4.1.1 在不同的 JAR 中加载 CDI bean

除非显式注释,否则不会发现 CDI bean

品Spring:对@Resource注解的处理方法

Bean和注入Bean的几种常用注解和区别

@SpringBootApplication包含的三个注解及其含义