一.Inject点(三种方式)
1.构造器依赖注入
public class SomeBean { private final Service service; @Inject public SomeBean(Service service){ this.service = service; } }
说明:每个Bean只能有一个@Inject方式的构造方法.
2.字段注入(推荐)
public class SomeBean { @Inject private Service service; }这种推荐定义为private.在这种情况下,当容器初始化一个SomeBean类型的bean将注入正确的Service bean,不需要任何setter方法。
3.初始化方法参数注入
public class SomeBean { private Service service; @Inject public void setService(Service service) { this.service = service; } }一般我不喜欢这么用. bean可以有多个初始化方法。
4.注入说明,顺序说明
依赖关系注入发生在容器第一次实例化bean 实例时。顺序如下:
- 容器调用bean构造函数(默认的构造函数或一个附加@Inject的构造函数),以获取 bean 的实例。
- 容器初始化 bean 的所有字段。
- 接下来,容器调用bean的所有初始化方法(调用顺序是不可移植的,不要依赖它)。
- 最后是标注了@PostConstruct方法.(如果有的话)
构造器----字段----初始化方法---@PostConstruct方法
注意:CDI还支持参数注入一些其他方法调用的容器。例如,参数注入是支持生产方法:
@Produces Checkout createCheckout(ShoppingCart cart) { return new Checkout(cart); }这种情况,是不需要@inject的.
二:Qualifier
Qualifier注解的作用在第一章已经说过.
比如我们有多个bean实现特定的bean类型,注入某个bean就必须应该使用限定符注释注入.
下面是第一个PaymentProcessor的Qualifier
@Qualifier @Retention(RUNTIME) @Target({TYPE,METHOD,FIELD,PARAMETER}) public @interface Synchronous {}
@Synchronous public class SynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }第二个:
@Qualifier @Retention(RUNTIME) @Target({TYPE,PARAMETER}) public @interface Asynchronous {}
@Asynchronous public class AsynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
1.构造器注入
@Inject public Checkout(@Synchronous PaymentProcessor syncPaymentProcessor,@Asynchronous PaymentProcessor asyncPaymentProcessor) { this.syncPaymentProcessor = syncPaymentProcessor; this.asyncPaymentProcessor = asyncPaymentProcessor; }
2.字段注入(推荐)
@Inject @Synchronous PaymentProcessor syncPaymentProcessor; @Inject @Asynchronous PaymentProcessor asyncPaymentProcessor;
3.初始化方法注入
public void setPaymentProcessors(@Synchronous PaymentProcessor syncPaymentProcessor,@Asynchronous PaymentProcessor asyncPaymentProcessor) { this.syncPaymentProcessor = syncPaymentProcessor; this.asyncPaymentProcessor = asyncPaymentProcessor; }
三:内置的Qualifiers==>@Default @Any
1.@Default
如果没有指定具体的qualifiers,那么系统默认加一个@Defaule.2.@Any用法
如果我们有多个Bean实现了某个接口,我们要注入所有的这个接口类型的托管Bean,如下面这种方式获取.public class SomeBean { @Inject public void listServiceImplementations( @Any Instance<Service> serviceList) { for(Service service : serviceList){ System.out.println(service.getClass().getCanonicalName()); } } }
四:Multiple qualifiers
Inject点可以指定多个限定符:@Synchronous @Reliable public class SynchronousReliablePaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }使用:
@Inject @Synchronous @Reliable PaymentProcessor syncPaymentProcessor;
五:Qualifiers的会员概念,用法
你会看到一种用法@Qualifier数符可以有成员。
这种方法将避免在单个应用程序中编写的@Qualifier数量太多造成爆炸.
@Qualifier @Retention(RUNTIME) @Target({METHOD,PARAMETER,TYPE}) public @interface Payment{ EnumMoneyType value(); }
//USD--美元 CNY--人民币 public enum EnumMoneyType{ USD,CNY; }我们在Qualifiers中加入了一个属性,为一个枚举,上面这个就是枚举.当然你可以使用默认值.这里我没写.下面就是使用这个Qualifier的2个示例:
@Payment(EnumMoneyType.USD) public class PRacquet implements RacquetType{ ..... }
@Payment(EnumMoneyType.CNY) public class FRacquet implements RacquetType{ ..... }我们也可以让容器忽视成员,用@Nonbinding限定符注释类型的成员容器就是忽略。
@Qualifier @Retention(RUNTIME) @Target({METHOD,TYPE}) public @interface Payment{ EnumMoneyType value(); //下面的comment将不起作用,被容器忽略 @Nonbinding String comment() default ""; }
四:通过编程获取上下文实例
在某些情况下,注入不是最方便的方式来获取上下文引用.
例如,
- bean类型或限定符在运行时动态地变化
- qualifiers和type不满足@Inject.
- 我们想要遍历所有某个type和qualifiers的Bean.
这种情况下,应该这样使用:
@InjectInstance<PaymentProcessor>paymentProcessorSource;实例的get() 方法创建的bean的上下文实例。这样也会有个延迟加载的意思在里面.
PaymentProcessorp=paymentProcessorSource.get();当然,按照我们在本章上面说的,也可以这样:
@Inject@AsynchronousInstance<PaymentProcessor>paymentProcessorSource;现在,返回的PaymentProcessor get()将是限定符为@Asynchronous的实例。
@Any+Instance select()
或者,我们可以动态地指定限定符。首先,我们将@Any限定符添加到注入点.
import javax.enterprise.inject.Instance; ... @Inject @Any Instance<PaymentProcessor> paymentProcessorSource;
接下来,我们需要获得我们的限定符类型的一个实例。因为注释是接口,我们不能只写新的Asynchronous().这也是非常乏味的从头创建一个注释类型的具体实现。相反,CDI让我们过AnnotationLiteral helper类获得一个限定符实例通。
class AsynchronousQualifier extends AnnotationLiteral<Asynchronous> implements Asynchronous {}在某些情况下,我们可以使用一个匿名类:
PaymentProcessor p = paymentProcessorSource.select(new AnnotationLiteral<Asynchronous>() {});然而,我们不能用一个匿名类实现一个限定符类型和成员。
所以我们可以通过qualifier of Instance select()方法。
Annotation qualifier = synchronously ? new SynchronousQualifier() : new AsynchronousQualifier(); PaymentProcessor p = anyPaymentProcessor.select(qualifier).get().process(payment);
五:InjectionPoint对象用法
比如说我们使用logger,是这样写
Logger log = Logger.getLogger(MyClass.class.getName());
但通过CDI InjectionPoint对象
import javax.enterprise.inject.spi.InjectionPoint; import javax.enterprise.inject.Produces; class LogFactory { @Produces Logger createLogger(InjectionPoint injectionPoint) { return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); } }
在其他的类中,可以如下代码这样注入
@InjectLoggerlog;容器提供了一个内置bean实现InjectionPoint接口:
public interface InjectionPoint { public Type getType(); public Set<Annotation> getQualifiers(); public Bean<?> getBean(); public Member getMember(); public Annotated getAnnotated(); public boolean isDelegate(); public boolean isTransient(); }