CDI(Weld)基础<3>依赖关系注入(DI)和编程查找

前端之家收集整理的这篇文章主要介绍了CDI(Weld)基础<3>依赖关系注入(DI)和编程查找前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一.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 实例时。顺序如下:

  1. 容器调用bean构造函数(默认的构造函数或一个附加@Inject的构造函数),以获取 bean 的实例。
  2. 容器初始化 bean 的所有字段。
  3. 接下来,容器调用bean的所有初始化方法(调用顺序是不可移植的,不要依赖它)。
  4. 最后是标注了@PostConstruct方法.(如果有的话)

构造器----字段----初始化方法---@PostConstruct方法

注意:
  • 需要注意的是,如果Bean的父类已经字段注入某个Bean.那之后这个Bean初始化方法参数注入方式会出问题.
  • 构造函数注入的一个主要优点是,它允许将bean不可变的。
  • @H_301_71@

    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 "";
    }

    四:通过编程获取上下文实例

    在某些情况下,注入不是最方便的方式来获取上下文引用.
    例如,

    1. bean类型或限定符在运行时动态地变化
    2. qualifiers和type不满足@Inject.
    3. 我们想要遍历所有某个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();
    }

猜你在找的设计模式相关文章