1.基本注入@Inject
字段,构造方法,方法体
2.瞬态注入@Inject Instance<T> myInstances;
当把一个依赖bean注入到一个长期存在的bean时,后者初始化时(@Inject)这个注入完成并只执行一次。
如果我想每次访问时都再次初始化并且重新注入时必须这样写:
@Inject Instance<MyBean> myBeanInstances;
public Mybean getMyBean() { return myBeanInstances.get(); }
而在CDI组的一个开发者,说希望CDI2.0变成
//现在还不是这样
@Inject @Transient MyBean myBean;
Bean 通常是一个包含业务逻辑的应用程序类。它可直接从 Java 代码中,调用或通过统一 EL 可能会调用它。Bean 可以访问事务性资源。Bean 之间的依赖关系由容器自动管理。大多数Bean是有状态和上下文。Bean 的生命周期是由容器进行管理。
第二方面,上下文真正意味着什么.由于一些Bean是有状态的.我们会有一个Bean实例.不同于无状态的组件模型(如EJB stateless session beans.)或一个单例组件模型(如servlet或单例bean),不同的用户用到/看到不同的Bean,然而,像一个无状态或单例模式,与有状态会话bean不同,客户端不控制实例的生命周期去显式地创建和销毁它。
相反,该 bean 的范围确定:生命周期的每个 bean 的实例和哪些客户端共享对该 bean 的特定实例的引用。
对于给定的线程在 CDI 应用程序中,可能与 bean 的范围关联活动上下文。这种情况下可能是唯一的线程 (例如,如果该 bean 是request scoped),或它可能与某些其他线程共享 (例如,如果该 bean 是session scoped),甚至其他所有线程 (如果它是application scoped)。客户端(例如,其他bean)执行相同的上下文将看到相同的bean的实例。
Bean types, qualifiers and dependency injection
要注入的Bean需要满足的条件是:
-
a bean type,
-
a set of qualifiers.
public class BookShop extends Business implements Shop<Book> {
...
}
上面代码的类型为BookShop ,Business ,Shop<Book>以及Object.
下面EJB的类型为:Business ,Shop<Book>以及Object.
@Stateful
public class BookShopBean extends Business implements BookShop, Auditable {
...
}
不是BookShop 类型是因为这个EJB不是客户端可见的Bean.
但是Bean可以显示的使用CDI注解 @TYPE 来指定Bean type.如下code:
@Typed(Shop.class)
public class BookShop extends Business implements Shop<Book> {
...
}
那么这个Bean的类型就限定为Shop,Object
有时,一个bean类型本身并没有提供足够的信息去知道到底哪个bean注入了容器。
例如,假设我们有两个PaymentProcessor接口的实现:CreditCardPaymentProcessor,DebitPaymentProcessor。
注入一个字段类型是PaymentProcessor的Bean将是不靠谱的,它会属于一种歧义类型.
在这些情况下,客户端必须重新进行明确的指定.
这时,我们可以使用CDI限定符注解:@Qualifier.它主要用来消除歧义类型.
如下,我们定义一个Qualifier:
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface CreditCard {}
接着,我们这样使用.
@CreditCard
public class CreditCardPaymentProcessor implements PaymentProcessor
{
...
}
我们已经定义了一个限定符注解,以及对CreditCardPaymentProcessor 进行了限定符的使用.我们可以使用它来消除歧义的注入点。如:
@Inject @CreditCard PaymentProcessor paymentProcessor
这就回到我们的开始说的,要注入的Bean需要满足的条件是:
-
a bean type,
-
a set of qualifiers.
注:
如果一个bean或注射点不明确指定一个限定词,他会有一个默认的限定词,就是@Default.
这只是简单的一种情况,后续还有其他情况的处理.慢慢来,不急.
更多详细参加后续文章.
Scope
bean定义了生命周期的范围和实例的可见性。CDI上下文模型是可扩展的,适应任意范围。然而,某些重要的范围是内置在规范,容器进行提供(如RequestScope,SessionScope,ConversationScope,applicationScope等)。
如下面的例子.
public @SessionScoped class ShoppingCart implements Serializable
{
...
}
请注意:一旦使用SessionScope,是没办法在上下文中手动删除Bean.除非上下文被销毁.
这种情况请考虑使用RequsetScope或ConversationScope.
如果未显式指定一个范围,然后该bean属于特殊的范围称为dependent pseudo-scope(依赖伪范围).如该bean被注入到SessionScope里,那该bean就是SessionScope.
更多详细参加后续文章.
EL Name
@Named 注释只是能够让页面使用EL,没有其他功能.最常见的就是JSF视图通过EL引用某个bean。
public @SessionScoped @Named("cart")class ShoppingCart implements Serializable { ... }
在JSF/JSP页面中如下使用:
<h:dataTable value="#{cart.lineItems}" var="item">
...
</h:dataTable>
如果@Named("cart")后面没有写("cart"),那默认值就是shoppingCart.
页面为:
<h:dataTable value="#{shoppingCart.lineItems}" var="item">
...
</h:dataTable>
Alternatives
我们已经看到在开发时限定符如何让我们一个接口选择多个实现。但有时我们有一个接口(或其他bean类型)的实现会根据部署环境的变化而变化。
public @Alternative class MockPaymentProcessor extends PaymentProcessorImpl { ... }
因此就会用到@Alternatives,在Bean.xml里进行相关的配置指定。具体后续再讲。或参考:http://my.oschina.net/zhaoqian/blog/119088
Interceptors
这个就暂时不讲,等后续有专门章节进行讲述。
2. What kinds of classes are beans?
1.ManagedBean
2.sessionBean(EJB Session Bean)
(就是EJB相关Bean,但不是消息驱动Bean和JPA实体,这2个非上下文对象,不能被注入的其他对象,但能注入其他对象,使用CDI其他功能。)
需要使用EJB的情况如下:
-
方法级别的事务管理和安全,
-
并发管理
-
有状态会话bean的实例级钝化
-
无状态会话bean实例池
-
远程或 web 服务调用
-
计时器和异步方法
3.Producer methods
Producer方法通过@Produces和定义quarfiler使用。
import javax.enterprise.inject.Produces;
@ApplicationScoped
public class RandomNumberGenerator {
private java.util.Random random = new java.util.Random(System.currentTimeMillis());
@Produces @Named @Random int getRandomNumber() {
return random.nextInt(100);
}
}
在其他页面调用:
@Inject @Random int randomNumber;
在JSF页面EL表达式为:
<p>Your raffle number is #{randomNumber}.</p>
这个是简单的应用,后续会有更详细说明。
4.Producer fields
这个可以说是Producer methods的简化版。具体待以后讲解。本章就先说到这里。