请尊重成果,如需转载请注明来源http://equalxx.iteye.com/
Chapter 2.More about beans关于bean的更多内容
bean一般是包含业务逻辑的应用类。可以直接被java代码调用,也可以在标准的EL表达式中调用。Bean也可以访问事务资源。Bean之间的依赖关系由容器自动管理,大多bean是有状态和上下文的。Bean的生命周期由容器管理。
让我们再看一下,到底什么叫“有上下文的”?bean有没有状态关系到我有哪个bean的实例。不像一个没有状态的组件模型(比如无状态会话bean)或是一个单例组件模型(比如servlets或是单例bean),有状态bean在不同的客户端有着不同的状态。是否标识用户可见状态(client-visible state)取决于客户端有没有对这个bean的实例的引用。
无状态或单例模型,不同于有状态会话bean,客户端不会通过显式地创建销毁它来控制它的生命周期。取而代之的是用bean scope来决定:
1、每个bean实例的生命周期
2、哪些客户端可以共享对bean的指定实例的引用
对于CDI应用的给定线程,可能会有一个通过bean scope关联的活动上下文。这个上下文在这个线程中可能是唯一的(比如这个bean是request scoped的),或是它也可能同时与其他线程共享(比如这个bean是session scoped的),甚至和所有其他线程共享(这用的是application scoped)。
执行在同一上下文中的客户端(比如说其他beans)用的都是同一个bean实例。但是在不同上下文中执行的客户端,用的是不同的实例(这取决于上下文之间的关系)。
上下文其中一项最大的优点就是它可以让状态bean像service一样。客户端不必去管理它的bean的生命周期,也不用知道bean的生命周期是什么。这些bean都是松耦合的,因为:
1、他们通过明确的公共API来管理相互间关系
2、它们的生命周期跟客户端完全解耦
我们可以把一个bean替换成继承同一个接口的另一个bean(这个bean可以有不同的生命周期(scope))而不用影响任何其他bean的实现。事实上,CDI提供了一个简单的方式在部署时重载,我们会在4.7节的“Alternatives”详细介绍。
要注意不是所有bean的客户端都是bean本身。其他对象,比如servlets或消息驱动bean(message-driven beans),他们都不是可注入到其他bean的上下文对象,但他们仍然能够通过注入获取对其他bean的引用。
2.1. The anatomy of a bean 对bean的解析
在此前我们已经铺垫了这么多,下面我们来正式地介绍bean,根据规范:
一个bean由以下属性组成:
1、一个(非空)bean类型集
2、一个(非空)限定符集
3、一个Scope
4、可选,一个bean EL name
5、一组拦截器绑定
6、一个bean的实现
此外,一个bean可能是alternativ的,也可能不是。
让我们去看看这些属性都是什么意思。
2.1.1 Bean types,qualifiers and dependency injection bean类型,限定符和依赖注入
Bean通常通过依赖注入获取对其他bean的引用。任何一个被注入的属性规定了一个“合同”,所有要注入的bean必须满足这个“合同”。这个“合同”就是:
1、bean type
2、一组限定符
bean type表明了bean是用户可见类型,它可以是用户定义的class或接口。如果bean是个EJB会话bean,那么它的bean type就是@Local接口,或是bean-class的本地视图。一个bean可能会有很多个bean type。比如说下面的bean有四个bean type:
public class BookShop
extends Business
implements Shop<Book> {
...
}
它的bean type是 BookShop,Business和Shop<Book>,以及隐式类型java.lang.Object。(注意,参数化类型是合法的bean类型)。
同时,下面这个会话bean只有本地的三个接口BookShop,Auditable和java.lang.Object可以作为bean type,但由于@Stateful,BookShopBean不是用户可见类型。
@Stateful
public class BookShopBean
extends Business
implements BookShop, Auditable {
...
}
注意:会话bean的bean type包括本地接口和bean类local view(如果有的话)。EJB远程接口不被认为是会话bean的bean type。你不能把一个EJB通过远程接口注入,除非你定义一个资源,这个会在Chapter 14,Java EE组件环境资源中介绍。
(译者注:其实这段光看英文感觉难以和实际使用关联起来,bean type到底讲了什么,查看了一些资料以后我认为可能是在说,bean通过可以通过不同的bean type注入,而bean type包含了什么内容,有个网址里面有说明http://moon26.blogspot.jp/2012/01/javaee6-cdi-bean-and-bean-types.html,我会接下来和同事一起讨论,它究竟在开发中处于什么角色,再来更新此部分内容)
Bean types可以通过@Typed注解来指定,同时列出所有应该为bean type的类。比如说这个bean types bean已经被限制为Shop<Book>和java.lang.Object:
@Typed(Shop.class)
public class BookShop
extends Business
implements Shop<Book> {
...
}
有时,仅有bean type的话并不能提供给容器足够的信息去让容器知道该注入哪个bean。举例说,假设我有两个实现了PaymentProcessor接口的实现类:CreditCardPaymentProcessor和DebitPaymentProcessor。如果把它俩注入到PaymentProcessor类型的域中,就会引起混淆。在这种情况下,用户必须提供更多的特性来告知容器应该注入哪一个。所以我们通过qualifier来指明特性。
一个qualifier是个用户定义的注解,用@Qualifier来定义。它是一个类型系统(type system)的一个扩展。它使我们不用基于名称来区分注入类型。以下就是个用@Qualifier注解的例子:
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface CreditCard {}
你可能还不习惯看到上面这样的创建注解的代码,有可能这是你第一次遇到这样定义。用CDI的话,定义注解将会成为你时不时需要去做的事儿。
注意:
请注意在CDI和EJB中的注解名称,你会发现他们多是形容词。我们鼓励您在创建自定义注解时候也遵循这种习惯,当它们是用来描述行为和指明类角色的时候。
现在我们已经定义了一个特性注解了,我们可以在注入点使用它来明确注入类。下面的注入点包含了bean类型PaymentProcessor以及qualifier @CreditCard:
@Inject @CreditCard PaymentProcessor paymentProcessor
注意:
若一个bean或是一个注入点没有被一个qualifier修饰,它会有一个默认修饰符@Default。
这还没结束,CDI还定义了一个简单的解决规则用来帮助容器该接下来怎么做,当多个bean同时满足“合同”的时候。我们会在Chapter 4,依赖注入和程序化查找章节讨论细节。
请尊重成果,如需转载请注明来源http://equalxx.iteye.com/