3.1 CDI中的Bean及其作用域
CDI中最基本的概念是Bean。Bean是创建上下文对象的模板,这些对象称为Bean的上下文对象实例。这里的上下文就是CDI名称中提到的Context,上下文是CDI规范中很重要的一个概念。CDI容器所管理的对象实例都与特定的上下文相关联。
CDI的Bean可以包含如下的属性。
· Bean类型的集合。
· 修饰符的集合。
· 作用域。
· 可选的Bean名称。
· 拦截器绑定的集合。
· Bean的实现。
· Bean是否作为替代。
在上述属性中,Bean的实现由开发人员以Java代码来编写。其他属性则以注解的形式出现在Bean类型上。如果没有显式的注解声明,Bean的属性会使用容器提供的默认值。
最常见的Bean是Java类。使用Java类的构造器可以创建出Bean的对象实例。一个Bean可以有多个类型。对于一个Java类来说,它的Bean类型包括它自身、它所有的父类以及它实现的全部接口的类型。比如下面代码中的UserServiceImpl类,它的Bean类型包括UserService-Impl、AbstractService和UserService。
对于一个Bean类型,可能有多个不同的Bean实现该类型。最常见的例子是Java接口的Bean类型。每个接口的实现类都可以作为该Bean类型的实现。
所有的Bean都有且仅有一个作用域(Scope)。作用域决定了Bean的对象实例的生命周期。CDI规范中定义了一些常用的作用域。应用也可以创建自定义的作用域。
作用域分成普通作用域和伪作用域(Pseudo Scope)两类。绝大部分作用域是普通作用域。作用域类型以注解类型来表示。CDI规范中定义了几个内置的作用域,相应的注解类型在javax.enterprise.context包中。表3-1列出了Quarkus支持的内置作用域。
表3-1 Quarkus的内置作用域
下面代码中的UserService使用了@ApplicationScope作为作用域。一般来说,应用的服务层Bean都使用@ApplicationScope或@Singleton作为作用域。因为这些Bean并没有内部的状态,可以安全地在不同组件之间共享。只有在REST API层,才可能用到@RequestScope和@Session-Scope作用域。
除了普通作用域之外的都称为伪作用域。@Dependent是CDI规范中定义的伪作用域。对于@Dependent作用域中的Bean,每个依赖注入点的对象实例都是不同的。