public class SomeBean { private final Service service; @Inject public SomeBean(Service service){ this.service = service; } }
说明:每个Bean只能有一个@Inject方式的构造方法.
public class SomeBean { @Inject private Service service; }这种推荐定义为private.在这种情况下,当容器初始化一个SomeBean类型的bean将注入正确的Service bean,不需要任何setter方法。
public class SomeBean { private Service service; @Inject public void setService(Service service) { this.service = service; } }一般我不喜欢这么用. bean可以有多个初始化方法。
依赖关系注入发生在容器第一次实例化bean 实例时。顺序如下:
构造器----字段----初始化方法---@PostConstruct方法
注意:CDI还支持参数注入一些其他方法调用的容器。例如,参数注入是支持生产方法:
@Produces Checkout createCheckout(ShoppingCart cart) { return new Checkout(cart); }这种情况,是不需要@inject的.
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, METHOD, FIELD, PARAMETER}) public @interface Asynchronous {}
@Asynchronous public class AsynchronousPaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }
@Inject public Checkout(@Synchronous PaymentProcessor syncPaymentProcessor, @Asynchronous PaymentProcessor asyncPaymentProcessor) { this.syncPaymentProcessor = syncPaymentProcessor; this.asyncPaymentProcessor = asyncPaymentProcessor; }
@Inject @Synchronous PaymentProcessor syncPaymentProcessor; @Inject @Asynchronous PaymentProcessor asyncPaymentProcessor;
public void setPaymentProcessors(@Synchronous PaymentProcessor syncPaymentProcessor, @Asynchronous PaymentProcessor asyncPaymentProcessor) { this.syncPaymentProcessor = syncPaymentProcessor; this.asyncPaymentProcessor = asyncPaymentProcessor; }
public class SomeBean { @Inject public void listServiceImplementations( @Any Instance<Service> serviceList) { for(Service service : serviceList){ System.out.println(service.getClass().getCanonicalName()); } } }
@Synchronous @Reliable public class SynchronousReliablePaymentProcessor implements PaymentProcessor { public void process(Payment payment) { ... } }使用:
@Inject @Synchronous @Reliable PaymentProcessor syncPaymentProcessor;
你会看到一种用法@Qualifier数符可以有成员。
这种方法将避免在单个应用程序中编写的@Qualifier数量太多造成爆炸.
@Qualifier @Retention(RUNTIME) @Target({METHOD, FIELD, 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, FIELD, PARAMETER, TYPE}) public @interface Payment{ EnumMoneyType value(); //下面的comment将不起作用,被容器忽略 @Nonbinding String comment() default ""; }
在某些情况下,注入不是最方便的方式来获取上下文引用.
例如,
这种情况下,应该这样使用:
@Inject Instance<PaymentProcessor> paymentProcessorSource;实例的get() 方法创建的bean的上下文实例。这样也会有个延迟加载的意思在里面.
PaymentProcessor p = paymentProcessorSource.get();当然, 按照我们在本章上面说的,也可以这样:
@Inject @Asynchronous Instance<PaymentProcessor> paymentProcessorSource;现在,返回的PaymentProcessor get()将是限定符为@Asynchronous的实例。
或者,我们可以动态地指定限定符。首先,我们将@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>() {});然而,我们不能用一个匿名类实现一个限定符类型和成员。
Annotation qualifier = synchronously ? new SynchronousQualifier() : new AsynchronousQualifier(); PaymentProcessor p = anyPaymentProcessor.select(qualifier).get().process(payment);
比如说我们使用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()); } }
在其他的类中,可以如下代码这样注入
@Inject Logger log;容器提供了一个内置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(); }